QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#548861#6637. Perfect StringsKirill22AC ✓2011ms3868kbC++2318.2kb2024-09-05 21:39:302024-09-05 21:39:30

Judging History

你现在查看的是最新测评结果

  • [2024-09-05 21:39:30]
  • 评测
  • 测评结果:AC
  • 用时:2011ms
  • 内存:3868kb
  • [2024-09-05 21:39:30]
  • 提交

answer

#include "bits/stdc++.h"

using namespace std;

/*
 ! WARNING: MOD must be prime.
 ! WARNING: MOD must be less than 2^30.
 * Use .get() to get the stored value.
 */
template<uint32_t mod>
class montgomery {
    static_assert(mod < uint32_t(1) << 30, "mod < 2^30");
    using mint = montgomery<mod>;

private:
    uint32_t value;

    static constexpr uint32_t inv_neg_mod = []() {
        uint32_t x = mod;
        for (int i = 0; i < 4; ++i) {
            x *= uint32_t(2) - mod * x;
        }
        return -x;
    }();
    static_assert(mod * inv_neg_mod == -1);

    static constexpr uint32_t neg_mod = (-uint64_t(mod)) % mod;

    static uint32_t reduce(const uint64_t &value) {
        return (value + uint64_t(uint32_t(value) * inv_neg_mod) * mod) >> 32;
    }

    inline static const mint ONE = mint(1);

public:
    montgomery() : value(0) {}
    montgomery(const mint &x) : value(x.value) {}

    template<typename T, typename U = std::enable_if_t<std::is_integral<T>::value>>
    montgomery(const T &x) : value(!x ? 0 : reduce(int64_t(x % int32_t(mod) + int32_t(mod)) * neg_mod)) {}

    static constexpr uint32_t get_mod() {
        return mod;
    }

    uint32_t get() const {
        auto real_value = reduce(value);
        return real_value < mod ? real_value : real_value - mod;
    }

    template<typename T>
    mint power(T degree) const {
        degree = (degree % int32_t(mod - 1) + int32_t(mod - 1)) % int32_t(mod - 1);
        mint prod = 1, a = *this;
        for (; degree > 0; degree >>= 1, a *= a)
            if (degree & 1)
                prod *= a;

        return prod;
    }

    mint inv() const {
        return power(-1);
    }

    mint& operator=(const mint &x) {
        value = x.value;
        return *this;
    }

    mint& operator+=(const mint &x) {
        if (int32_t(value += x.value - (mod << 1)) < 0) {
            value += mod << 1;
        }
        return *this;
    }

    mint& operator-=(const mint &x) {
        if (int32_t(value -= x.value) < 0) {
            value += mod << 1;
        }
        return *this;
    }

    mint& operator*=(const mint &x) {
        value = reduce(uint64_t(value) * x.value);
        return *this;
    }

    mint& operator/=(const mint &x) {
        return *this *= x.inv();
    }

    friend mint operator+(const mint &x, const mint &y) {
        return mint(x) += y;
    }

    friend mint operator-(const mint &x, const mint &y) {
        return mint(x) -= y;
    }

    friend mint operator*(const mint &x, const mint &y) {
        return mint(x) *= y;
    }

    friend mint operator/(const mint &x, const mint &y) {
        return mint(x) /= y;
    }

    mint& operator++() {
        return *this += ONE;
    }

    mint& operator--() {
        return *this -= ONE;
    }

    mint operator++(int) {
        mint prev = *this;
        *this += ONE;
        return prev;
    }

    mint operator--(int) {
        mint prev = *this;
        *this -= ONE;
        return prev;
    }

    mint operator-() const {
        return mint(0) - *this;
    }

    bool operator==(const mint &x) const {
        return get() == x.get();
    }

    bool operator!=(const mint &x) const {
        return get() != x.get();
    }

    bool operator<(const mint &x) const {
        return get() < x.get();
    }

    template<typename T>
    explicit operator T() {
        return get();
    }

    friend std::istream& operator>>(std::istream &in, mint &x) {
        std::string s;
        in >> s;
        x = 0;
        bool neg = s[0] == '-';
        for (const auto c : s)
            if (c != '-')
                x = x * 10 + (c - '0');

        if (neg)
            x *= -1;

        return in;
    }

    friend std::ostream& operator<<(std::ostream &out, const mint &x) {
        return out << x.get();
    }

    static int32_t primitive_root() {
        if constexpr (mod == 1'000'000'007)
            return 5;
        if constexpr (mod == 998'244'353)
            return 3;
        if constexpr (mod == 786433)
            return 10;

        static int root = -1;
        if (root != -1)
            return root;

        std::vector<int> primes;
        int value = mod - 1;
        for (int i = 2; i * i <= value; i++)
            if (value % i == 0) {
                primes.push_back(i);
                while (value % i == 0)
                    value /= i;
            }

        if (value != 1)
            primes.push_back(value);

        for (int r = 2;; r++) {
            bool ok = true;
            for (auto p : primes)
                if ((mint(r).power((mod - 1) / p)).get() == 1) {
                    ok = false;
                    break;
                }

            if (ok)
                return root = r;
        }
    }
};

constexpr uint32_t MOD = 1'000'000'007;
//constexpr uint32_t MOD = 998'244'353;
using mint = montgomery<MOD>;

namespace berlekamp_massey {
    template<typename T>
    std::vector<T> find_recurrence(const std::vector<T> &values) {
        if (values.empty())
            return {};

        std::vector<T> add_option{}, recurrence{};
        int add_position = -1;
        T add_value = values[1];
        for (int i = 0; i < int(values.size()); i++) {
            T value = 0;
            for (int j = 0; j < int(recurrence.size()); j++)
                value += values[i - j - 1] * recurrence[j];

            T delta = values[i] - value;
            if (delta == 0)
                continue;

            std::vector<T> new_recurrence;
            if (add_position == -1) {
                new_recurrence.assign(i + 1, 0);
            } else {
                new_recurrence = add_option;
                std::reverse(new_recurrence.begin(), new_recurrence.end());
                new_recurrence.push_back(-1);
                for (int it = 0; it < i - add_position - 1; it++)
                    new_recurrence.push_back(0);

                std::reverse(new_recurrence.begin(), new_recurrence.end());
                T coeff = -delta / add_value;
                for (auto &x : new_recurrence)
                    x *= coeff;

                if (new_recurrence.size() < recurrence.size())
                    new_recurrence.resize(recurrence.size());

                for (int i = 0; i < int(recurrence.size()); i++)
                    new_recurrence[i] += recurrence[i];
            }

            if (i - int(recurrence.size()) >= add_position - int(add_option.size()) || add_position == -1) {
                add_option = recurrence;
                add_position = i;
                add_value = delta;
            }
            recurrence = new_recurrence;
        }
        return recurrence;
    }

    template<typename T>
    std::vector<T> multiply(const std::vector<T> &first, const std::vector<T> &second) {
        // can be replaced with fft multiplication
        std::vector<T> prod(std::max(0, int(first.size() + second.size()) - 1));
        for (int i = 0; i < int(first.size()); i++)
            for (int j = 0; j < int(second.size()); j++)
                prod[i + j] += first[i] * second[j];

        return prod;
    }

    template<typename T>
    std::vector<T> find_remainder(std::vector<T> first, const std::vector<T> &second) {
        // can be replaced with fft division
        if (second.empty())
            return {};

        assert(second.back() != 0);
        while (!first.empty() && first.size() >= second.size()) {
            if (first.back() == 0) {
                first.pop_back();
                continue;
            }
            T coeff = first.back() / second.back();
            for (int i = 0; i < int(second.size()); i++)
                first[int(first.size()) - int(second.size()) + i] -= coeff * second[i];
        }
        return first;
    }

    template<typename T>
    std::vector<T> find_remainder(std::vector<T> recurrence, int64_t k) {
        while (!recurrence.empty() && recurrence.back() == 0)
            recurrence.pop_back();

        std::vector<T> result{1}, value{0, 1};
        for (; k; k >>= 1) {
            if (k & 1)
                result = find_remainder(multiply(result, value), recurrence);

            value = find_remainder(multiply(value, value), recurrence);
        }
        return result;
    }

    template<typename T>
    T find_kth(const std::vector<T> &values, std::vector<T> recurrence, int64_t k) {
        std::reverse(recurrence.begin(), recurrence.end());
        recurrence.push_back(-1);
        std::vector<T> poly = find_remainder(recurrence, k);
        T result = 0;
        for (int i = 0; i < int(poly.size()); i++)
            result += poly[i] * values[i];

        return result;
    }
} // berlekamp_massey

/*
 * Include static_modular_int to use it.
 * No need to run any init function.
 * If MOD is not prime inv and ifact won't be correct.
*/

namespace combinatorics {
    std::vector<mint> fact_, ifact_, inv_;

    void reserve(int size) {
        fact_.reserve(size + 1);
        ifact_.reserve(size + 1);
        inv_.reserve(size + 1);
    }

    void resize(int size) {
        if (fact_.empty()) {
            fact_ = {mint(1), mint(1)};
            ifact_ = {mint(1), mint(1)};
            inv_ = {mint(0), mint(1)};
        }
        for (int pos = fact_.size(); pos <= size; pos++) {
            fact_.push_back(fact_.back() * mint(pos));
            inv_.push_back(-inv_[MOD % pos] * mint(MOD / pos));
            ifact_.push_back(ifact_.back() * inv_[pos]);
        }
    }

    struct combinatorics_info {
        std::vector<mint> &data;

        combinatorics_info(std::vector<mint> &data) : data(data) {}

        mint operator[](int pos) {
            if (pos >= int(data.size()))
                resize(pos);

            return data[pos];
        }
    } fact(fact_), ifact(ifact_), inv(inv_);

    // From n choose k.
    mint choose(int n, int k) {
        if (n < k || k < 0 || n < 0)
            return mint(0);

        return fact[n] * ifact[k] * ifact[n - k];
    }

    // From n choose k.
    // O(min(k, n - k)).
    mint choose_slow(int n, int k) {
        if (n < k || k < 0 || n < 0)
            return mint(0);

        k = std::min(k, n - k);
        mint result = 1;
        for (int i = k; i >= 1; i--) {
            result *= (n - i + 1);
            result *= inv[i];
        }
        return result;
    }
}

using combinatorics::fact;
using combinatorics::ifact;
using combinatorics::inv;
using combinatorics::choose;
using combinatorics::choose_slow;

std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

int gen(int l, int r) {
    return std::uniform_int_distribution<int>(l, r)(rng);
}

struct sparse_matrix {
    int n;
    std::vector<std::vector<std::pair<int, mint>>> a;

    sparse_matrix(int n) : n(n) {
        a.resize(n);
    }

    void add(int i, int j, mint x) {
        a[i].emplace_back(j, x);
    }

    std::vector<mint> mul_right(const std::vector<mint>& rhs) const {
        std::vector<mint> res(n);
        for (int i = 0; i < n; i++) {
            for (auto& j : a[i]) {
                res[i] += j.second * rhs[j.first];
            }
        }
        return res;
    }

    std::vector<mint> mul_left(const std::vector<mint> &lhs) const {
        std::vector<mint> res(n);
        for (int i = 0; i < n; i++) {
            for (auto& j : a[i]) {
                res[j.first] += j.second * lhs[j.first];
            }
        }
        return res;
    }

    std::vector<mint> minimal_polynomial() const {
        std::vector<mint> v(n), u(n), val(2 * n + 1);
        for (int i = 0; i < n; i++) {
            v[i] = gen(1, MOD - 1);
            u[i] = gen(1, MOD - 1);
        }
        for (int i = 0; i < 2 * n + 1; i++) {
            for (int j = 0; j < n; j++) {
                val[i] += v[j] * u[j];
            }
            u = mul_right(u);
        }
        std::vector<mint> now = berlekamp_massey::find_recurrence(val);
        reverse(now.begin(), now.end());
        return now;
    }

    mint determinant() {
        if (!n) {
            return mint(1);
        }
        std::vector<mint> r(n);
        mint p = 1;
        for (int i = 0; i < n; i++) {
            r[i] = gen(1, MOD - 1);
            p *= r[i];
            for (auto& j : a[i]) {
                j.second *= r[i];
            }
        }
        std::vector<mint> res = minimal_polynomial();
        for (int i = 0; i < n; i++) {
            mint inv = mint(1) / r[i];
            for (auto& j : a[i]) {
                j.second *= inv;
            }
        }
        if ((int) res.size() != n) {
            return mint(0);
        }
        mint ans = res[0] / p;
        if (n % 2 == 0) {
            ans *= -1;
        }
        return ans;
    }

    std::vector<mint> power(const std::vector<mint>& b, long long k) const {
        std::vector<mint> v(n), u = b, val(2 * n + 1);
        std::vector<std::vector<mint>> save(n);
        for (int i = 0; i < n; i++) {
            v[i] = gen(1, MOD - 1);
        }
        for (int i = 0; i < 2 * n + 1; i++) {
            if (i < n) {
                save[i] = u;
            }
            for (int j = 0; j < n; j++) {
                val[i] += v[j] * u[j];
            }
            u = mul_right(u);
        }
        std::vector<mint> res = berlekamp_massey::find_recurrence(val);
        std::vector<mint> A(res.size());
        std::vector<mint> ans(n);
        std::reverse(res.begin(), res.end());
        res.push_back(-1);
        auto pol = berlekamp_massey::find_remainder(res, k);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j + 1 < (int) res.size(); j++) {
                A[j] = save[j][i];
            }
            if (k + 1 < res.size()) {
                ans[i] = A[k];
            } else {
                for (int j = 0; j + 1 < (int) res.size(); j++) {
                    ans[i] += pol[j] * A[j];
                }

            }
        }
        return ans;
    }

    std::vector<mint> solve_system(const std::vector<mint>& b) const {
        std::vector<mint> v(n), u = b, val(2 * n + 1), prv;
        std::vector<std::vector<mint>> save(n);
        for (int i = 0; i < n; i++) {
            v[i] = gen(1, MOD - 1);
        }
        for (int i = 0; i < 2 * n + 1; i++) {
            val[i] = 0;
            if (i < n) {
                save[i] = u;
            }
            for (int j = 0; j < n; j++) {
                val[i] += v[j] * u[j];
            }
            u = mul_right(u);
        }
        std::vector<mint> res = berlekamp_massey::find_recurrence(val);
        reverse(res.begin(), res.end());
        if (res[0] == mint(0)) {
            return {}; // determinant is zero probably
        }
        for (auto& i : res) {
            i *= -1;
        }
        res.emplace_back(1);
        std::vector<mint> ans(n);
        for (int i = 1; i < (int) res.size(); i++) {
            for (int j = 0; j < n; j++) {
                ans[j] += res[i] * save[i - 1][j];
            }
        }
        mint inv = -mint(1) / res[0];
        for (int i = 0; i < n; i++) {
            ans[i] *= inv;
        }
        return ans;
    }
};

vector<vector<mint>> operator+(const vector<vector<mint>>& a, const vector<vector<mint>>& b) {
    int n = (int) a[0].size();
    vector res(n, vector<mint>(n, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            res[i][j] = a[i][j] + b[i][j];
        }
    }
    return res;
}

vector<vector<mint>> operator*(const vector<vector<mint>>& a, const vector<vector<mint>>& b) {
    int n = (int) a[0].size();
    vector res(n, vector<mint>(n, 0));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
                res[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return res;
}

std::vector<std::vector<mint>> Matrix_recurrence(std::vector<std::vector<std::vector<mint>>> a, long long k) {
    if (k < (long long) a.size()) {
        return a[k];
    }
    assert(!a.empty());
    const int n = (int) a[0].size();
    assert((int) a[0][0].size() == n);
    std::vector<mint> v(n), u(n), du(n), val(a.size());
    for (int i = 0; i < n; i++) {
        v[i] = gen(1, MOD - 1);
        u[i] = gen(1, MOD - 1);
    }
    for (int i = 0; i < (int) a.size(); i++) {
        for (int j = 0; j < n; j++) {
            for (int t = 0; t < n; t++) {
                val[i] += v[j] * a[i][j][t] * u[t];
            }
        }
    }
    std::vector<mint> res = berlekamp_massey::find_recurrence(val);
    std::vector<std::vector<mint>> ans(n, std::vector<mint> (n));
    std::reverse(res.begin(), res.end());
    res.push_back(-1);
    auto pol = berlekamp_massey::find_remainder(res, k);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int t = 0; t + 1 < (int) res.size(); t++) {
                ans[i][j] += pol[t] * a[t][i][j];
            }
        }
    }
    return ans;
}

constexpr int mod = 1e9 + 7;

auto& add(auto&& a, auto b) { return a = (a + b) % mod; }
auto& mul(auto&& a, auto b) { return a = a * uint64_t(b) % mod; }

void solve () {
    int n, c;
    cin >> n >> c;
    if (c == 1) {
        cout << 1 << '\n';
        return;
    }
    mint k = mint(2) * mint(c - 1) / mint(c);
    mint div = mint(k - 1) * mint(k - 1) - 1;
    // 1 - ax
    mint a = mint(4 - 4 * c) / div;
    mint ans = mint(k) * mint(k - 1) * mint(a).power(n);
    mint C = 1;
//    cout << k << " " << div << " " << a << " " << ans << endl;
    mint tmp = a.power(n), tmp2 = 1;
    mint inva = mint(1) / a;
    for (int i = 0; i <= n; i++) {
        ans -= k * C * tmp2 * tmp;
        tmp2 *= mint(-4 * (c - 1));
        tmp *= inva;
//        cout << i << " " << ans << " " << C << endl;
        C *= mint(1 - 2 * i) / mint(2);
        C /= mint(i + 1);
    }
    ans /= div;
    cout << ans << '\n';
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3632kb

input:

2
3 1
2 2

output:

1
6

result:

ok 2 number(s): "1 6"

Test #2:

score: 0
Accepted
time: 109ms
memory: 3584kb

input:

100000
1 1
4 1
5 5
3 5
1 2
5 3
1 1
3 3
5 2
2 1
4 1
5 5
2 3
4 1
3 3
2 5
3 2
4 3
4 4
3 5
3 1
5 2
2 2
4 2
5 4
1 2
3 1
4 5
2 5
5 3
1 5
5 2
3 2
5 2
4 1
1 3
3 2
4 5
2 1
4 1
2 2
1 1
3 5
4 5
2 3
3 5
2 5
2 4
5 4
2 3
1 1
2 1
4 4
1 5
5 4
1 3
5 4
4 5
1 3
1 1
3 3
2 4
2 4
2 1
5 5
1 3
2 3
4 1
4 3
2 4
2 4
4 2
1 1
1...

output:

1
1
71445
485
2
3543
1
87
252
1
1
71445
15
1
87
45
20
543
2092
485
1
252
6
70
19864
2
1
5725
45
3543
5
252
20
252
1
3
20
5725
1
1
6
1
485
5725
15
485
45
28
19864
15
1
1
2092
5
19864
3
19864
5725
3
1
87
28
28
1
71445
3
15
1
543
28
28
70
1
1
71445
15
2092
3
1
2
15
87
2092
19864
71445
6
252
2092
252
15...

result:

ok 100000 numbers

Test #3:

score: 0
Accepted
time: 1093ms
memory: 3680kb

input:

100000
94 7867320
84 1294950
35 8570570
72 7050952
23 3907221
95 7482398
58 2363048
44 2234552
50 8809524
37 1061961
19 884367
38 3261675
59 1563189
61 7603994
83 3131714
19 6207284
64 5662457
2 6845951
84 4688192
13 7552675
38 3119650
84 6311084
10 5040332
53 5981961
46 7308176
43 679952
30 2922213...

output:

89775996
781446171
477730749
425095995
683480274
139962614
676040688
83128356
609223622
595772607
273248526
319532567
917638183
692265001
864029162
41269371
365591107
82686713
397805948
799200818
123574040
576607518
6430981
978266206
446712393
201799413
709622262
325465125
319418065
850111422
513285...

result:

ok 100000 numbers

Test #4:

score: 0
Accepted
time: 2011ms
memory: 3716kb

input:

18170
339 1623650
128 3200275
965 1829351
997 1547816
435 9138202
974 1806376
560 1011936
345 3813921
938 2229395
994 2411734
163 6603389
837 1133885
494 1068385
197 9254017
617 9553650
136 5850880
376 8616282
456 5759693
302 515509
293 2633903
703 7929747
205 5091361
303 5968505
740 872272
246 4106...

output:

461108227
93969714
967535558
286996770
439955818
513651814
367718117
70089455
537505709
989455211
600861203
892954232
899899624
825588888
536671357
118059202
325888233
146830823
953101687
974677182
364272875
482192182
565890497
657497852
297995102
797194699
322320804
744121644
399550079
576261681
42...

result:

ok 18170 numbers

Test #5:

score: 0
Accepted
time: 1995ms
memory: 3632kb

input:

176
15130 5219515
54554 814733
69310 3225417
43446 3402232
76425 3330887
34830 2231162
47132 342177
79713 4699528
48406 1562867
21339 5382282
34946 1991698
15555 4141661
52222 2028547
46168 5336018
52551 3781122
23469 1309869
86778 5167485
91984 6969638
28587 3283991
61602 8233067
59908 7918245
6735...

output:

819064610
746619602
481292930
837614851
505712843
251469513
848664626
555419188
788141020
910120658
97942397
995461053
434307672
778837756
976339209
531426099
871529896
875150459
25421918
983527791
281476053
75045944
504006808
866398210
213458087
196306823
900182966
590704432
289412620
28788603
7631...

result:

ok 176 numbers

Test #6:

score: 0
Accepted
time: 1811ms
memory: 3632kb

input:

13
931768 3882995
670768 6406509
941049 8590729
817046 5807892
779381 8981570
680279 9990918
396926 9134499
722228 9178753
561021 6110788
686746 6740122
458271 3748820
854144 5848248
548582 8566164

output:

268755962
578943126
92794411
444457165
169780513
804005790
351652199
721238566
102253686
200247655
716047991
465958249
717148868

result:

ok 13 numbers

Test #7:

score: 0
Accepted
time: 1721ms
memory: 3636kb

input:

5
1921421 2863210
1611550 9114363
1800313 2824695
1973050 2501730
1312507 7997456

output:

398101698
182608998
453457939
585926383
479930575

result:

ok 5 number(s): "398101698 182608998 453457939 585926383 479930575"

Test #8:

score: 0
Accepted
time: 2002ms
memory: 3632kb

input:

1
10000000 5350652

output:

694744897

result:

ok 1 number(s): "694744897"

Test #9:

score: 0
Accepted
time: 0ms
memory: 3868kb

input:

1
10000000 1

output:

1

result:

ok 1 number(s): "1"

Test #10:

score: 0
Accepted
time: 1912ms
memory: 3692kb

input:

1
9587024 1628294

output:

983037582

result:

ok 1 number(s): "983037582"

Test #11:

score: 0
Accepted
time: 2002ms
memory: 3628kb

input:

1
9994540 7861359

output:

145678106

result:

ok 1 number(s): "145678106"

Test #12:

score: 0
Accepted
time: 2001ms
memory: 3576kb

input:

1
9993434 8756421

output:

980562657

result:

ok 1 number(s): "980562657"

Test #13:

score: 0
Accepted
time: 2001ms
memory: 3572kb

input:

1
9999982 9427845

output:

977921308

result:

ok 1 number(s): "977921308"