QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#569606#9330. Series Sumucup-team004#AC ✓1472ms63748kbC++2016.3kb2024-09-17 01:22:492024-09-17 01:22:51

Judging History

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

  • [2024-09-17 01:22:51]
  • 评测
  • 测评结果:AC
  • 用时:1472ms
  • 内存:63748kb
  • [2024-09-17 01:22:49]
  • 提交

answer

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
template<class T>
constexpr T power(T a, i64 b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(i64 x) : x{norm(x % getMod())} {}
    
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        i64 v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
int MInt<0>::Mod = 1;

template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

constexpr int P = 998244353;
using Z = MInt<P>;

std::vector<int> rev;
template<int P>
std::vector<MInt<P>> roots{0, 1};

template<int P>
constexpr MInt<P> findPrimitiveRoot() {
    MInt<P> i = 2;
    int k = __builtin_ctz(P - 1);
    while (true) {
        if (power(i, (P - 1) / 2) != 1) {
            break;
        }
        i += 1;
    }
    return power(i, (P - 1) >> k);
}

template<int P>
constexpr MInt<P> primitiveRoot = findPrimitiveRoot<P>();

template<>
constexpr MInt<998244353> primitiveRoot<998244353> {31};

template<int P>
constexpr void dft(std::vector<MInt<P>> &a) {
    int n = a.size();
    
    if (int(rev.size()) != n) {
        int k = __builtin_ctz(n) - 1;
        rev.resize(n);
        for (int i = 0; i < n; i++) {
            rev[i] = rev[i >> 1] >> 1 | (i & 1) << k;
        }
    }
    
    for (int i = 0; i < n; i++) {
        if (rev[i] < i) {
            std::swap(a[i], a[rev[i]]);
        }
    }
    if (roots<P>.size() < n) {
        int k = __builtin_ctz(roots<P>.size());
        roots<P>.resize(n);
        while ((1 << k) < n) {
            auto e = power(primitiveRoot<P>, 1 << (__builtin_ctz(P - 1) - k - 1));
            for (int i = 1 << (k - 1); i < (1 << k); i++) {
                roots<P>[2 * i] = roots<P>[i];
                roots<P>[2 * i + 1] = roots<P>[i] * e;
            }
            k++;
        }
    }
    for (int k = 1; k < n; k *= 2) {
        for (int i = 0; i < n; i += 2 * k) {
            for (int j = 0; j < k; j++) {
                MInt<P> u = a[i + j];
                MInt<P> v = a[i + j + k] * roots<P>[k + j];
                a[i + j] = u + v;
                a[i + j + k] = u - v;
            }
        }
    }
}

template<int P>
constexpr void idft(std::vector<MInt<P>> &a) {
    int n = a.size();
    std::reverse(a.begin() + 1, a.end());
    dft(a);
    MInt<P> inv = (1 - P) / n;
    for (int i = 0; i < n; i++) {
        a[i] *= inv;
    }
}

template<int P = 998244353>
struct Poly : public std::vector<MInt<P>> {
    using Value = MInt<P>;
    
    Poly() : std::vector<Value>() {}
    explicit constexpr Poly(int n) : std::vector<Value>(n) {}
    
    explicit constexpr Poly(const std::vector<Value> &a) : std::vector<Value>(a) {}
    constexpr Poly(const std::initializer_list<Value> &a) : std::vector<Value>(a) {}
    
    template<class InputIt, class = std::_RequireInputIter<InputIt>>
    explicit constexpr Poly(InputIt first, InputIt last) : std::vector<Value>(first, last) {}
    
    template<class F>
    explicit constexpr Poly(int n, F f) : std::vector<Value>(n) {
        for (int i = 0; i < n; i++) {
            (*this)[i] = f(i);
        }
    }
    
    constexpr Poly shift(int k) const {
        if (k >= 0) {
            auto b = *this;
            b.insert(b.begin(), k, 0);
            return b;
        } else if (this->size() <= -k) {
            return Poly();
        } else {
            return Poly(this->begin() + (-k), this->end());
        }
    }
    constexpr Poly trunc(int k) const {
        Poly f = *this;
        f.resize(k);
        return f;
    }
    constexpr friend Poly operator+(const Poly &a, const Poly &b) {
        Poly res(std::max(a.size(), b.size()));
        for (int i = 0; i < a.size(); i++) {
            res[i] += a[i];
        }
        for (int i = 0; i < b.size(); i++) {
            res[i] += b[i];
        }
        return res;
    }
    constexpr friend Poly operator-(const Poly &a, const Poly &b) {
        Poly res(std::max(a.size(), b.size()));
        for (int i = 0; i < a.size(); i++) {
            res[i] += a[i];
        }
        for (int i = 0; i < b.size(); i++) {
            res[i] -= b[i];
        }
        return res;
    }
    constexpr friend Poly operator-(const Poly &a) {
        std::vector<Value> res(a.size());
        for (int i = 0; i < int(res.size()); i++) {
            res[i] = -a[i];
        }
        return Poly(res);
    }
    constexpr friend Poly operator*(Poly a, Poly b) {
        if (a.size() == 0 || b.size() == 0) {
            return Poly();
        }
        if (a.size() < b.size()) {
            std::swap(a, b);
        }
        int n = 1, tot = a.size() + b.size() - 1;
        while (n < tot) {
            n *= 2;
        }
        if (((P - 1) & (n - 1)) != 0 || b.size() < 128) {
            Poly c(a.size() + b.size() - 1);
            for (int i = 0; i < a.size(); i++) {
                for (int j = 0; j < b.size(); j++) {
                    c[i + j] += a[i] * b[j];
                }
            }
            return c;
        }
        a.resize(n);
        b.resize(n);
        dft(a);
        dft(b);
        for (int i = 0; i < n; ++i) {
            a[i] *= b[i];
        }
        idft(a);
        a.resize(tot);
        return a;
    }
    constexpr friend Poly operator*(Value a, Poly b) {
        for (int i = 0; i < int(b.size()); i++) {
            b[i] *= a;
        }
        return b;
    }
    constexpr friend Poly operator*(Poly a, Value b) {
        for (int i = 0; i < int(a.size()); i++) {
            a[i] *= b;
        }
        return a;
    }
    constexpr friend Poly operator/(Poly a, Value b) {
        for (int i = 0; i < int(a.size()); i++) {
            a[i] /= b;
        }
        return a;
    }
    constexpr Poly &operator+=(Poly b) {
        return (*this) = (*this) + b;
    }
    constexpr Poly &operator-=(Poly b) {
        return (*this) = (*this) - b;
    }
    constexpr Poly &operator*=(Poly b) {
        return (*this) = (*this) * b;
    }
    constexpr Poly &operator*=(Value b) {
        return (*this) = (*this) * b;
    }
    constexpr Poly &operator/=(Value b) {
        return (*this) = (*this) / b;
    }
    constexpr Poly deriv() const {
        if (this->empty()) {
            return Poly();
        }
        Poly res(this->size() - 1);
        for (int i = 0; i < this->size() - 1; ++i) {
            res[i] = (i + 1) * (*this)[i + 1];
        }
        return res;
    }
    constexpr Poly integr() const {
        Poly res(this->size() + 1);
        for (int i = 0; i < this->size(); ++i) {
            res[i + 1] = (*this)[i] / (i + 1);
        }
        return res;
    }
    constexpr Poly inv(int m) const {
        Poly x{(*this)[0].inv()};
        int k = 1;
        while (k < m) {
            k *= 2;
            x.resize(2 * k);
            Poly<P> y(2 * k);
            for (int i = 0; i < k && i < this->size(); i++) {
                y[i] = (*this)[i];
            }
            dft(x);
            dft(y);
            for (int i = 0; i < 2 * k; i++) {
                x[i] = x[i] * (2 - y[i] * x[i]);
            }
            idft(x);
            x.resize(k);
        }
        return x.trunc(m);
    }
    constexpr Poly log(int m) const {
        return (deriv() * inv(m)).integr().trunc(m);
    }
    constexpr Poly exp(int m) const {
        Poly x{1};
        int k = 1;
        while (k < m) {
            k *= 2;
            x = (x * (Poly{1} - x.log(k) + trunc(k))).trunc(k);
        }
        return x.trunc(m);
    }
    constexpr Poly pow(int k, int m) const {
        int i = 0;
        while (i < this->size() && (*this)[i] == 0) {
            i++;
        }
        if (i == this->size() || 1LL * i * k >= m) {
            return Poly(m);
        }
        Value v = (*this)[i];
        auto f = shift(-i) * v.inv();
        return (f.log(m - i * k) * k).exp(m - i * k).shift(i * k) * power(v, k);
    }
    constexpr Poly sqrt(int m) const {
        Poly x{1};
        int k = 1;
        while (k < m) {
            k *= 2;
            x = (x + (trunc(k) * x.inv(k)).trunc(k)) * CInv<2, P>;
        }
        return x.trunc(m);
    }
    constexpr Poly mulT(Poly b) const {
        if (b.size() == 0) {
            return Poly();
        }
        int n = b.size();
        std::reverse(b.begin(), b.end());
        return ((*this) * b).shift(-(n - 1));
    }
    constexpr std::vector<Value> eval(std::vector<Value> x) const {
        if (this->size() == 0) {
            return std::vector<Value>(x.size(), 0);
        }
        const int n = std::max(x.size(), this->size());
        std::vector<Poly> q(4 * n);
        std::vector<Value> ans(x.size());
        x.resize(n);
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                q[p] = Poly{1, -x[l]};
            } else {
                int m = (l + r) / 2;
                build(2 * p, l, m);
                build(2 * p + 1, m, r);
                q[p] = q[2 * p] * q[2 * p + 1];
            }
        };
        build(1, 0, n);
        std::function<void(int, int, int, const Poly &)> work = [&](int p, int l, int r, const Poly &num) {
            if (r - l == 1) {
                if (l < int(ans.size())) {
                    ans[l] = num[0];
                }
            } else {
                int m = (l + r) / 2;
                work(2 * p, l, m, num.mulT(q[2 * p + 1]).trunc(m - l));
                work(2 * p + 1, m, r, num.mulT(q[2 * p]).trunc(r - m));
            }
        };
        work(1, 0, n, mulT(q[1].inv(n)));
        return ans;
    }
};

template<int P = 998244353>
Poly<P> berlekampMassey(const Poly<P> &s) {
    Poly<P> c;
    Poly<P> oldC;
    int f = -1;
    for (int i = 0; i < s.size(); i++) {
        auto delta = s[i];
        for (int j = 1; j <= c.size(); j++) {
            delta -= c[j - 1] * s[i - j];
        }
        if (delta == 0) {
            continue;
        }
        if (f == -1) {
            c.resize(i + 1);
            f = i;
        } else {
            auto d = oldC;
            d *= -1;
            d.insert(d.begin(), 1);
            MInt<P> df1 = 0;
            for (int j = 1; j <= d.size(); j++) {
                df1 += d[j - 1] * s[f + 1 - j];
            }
            assert(df1 != 0);
            auto coef = delta / df1;
            d *= coef;
            Poly<P> zeros(i - f - 1);
            zeros.insert(zeros.end(), d.begin(), d.end());
            d = zeros;
            auto temp = c;
            c += d;
            if (i - temp.size() > f - oldC.size()) {
                oldC = temp;
                f = i;
            }
        }
    }
    c *= -1;
    c.insert(c.begin(), 1);
    return c;
}


template<int P = 998244353>
MInt<P> linearRecurrence(Poly<P> p, Poly<P> q, i64 n) {
    int m = q.size() - 1;
    while (n > 0) {
        auto newq = q;
        for (int i = 1; i <= m; i += 2) {
            newq[i] *= -1;
        }
        auto newp = p * newq;
        newq = q * newq;
        for (int i = 0; i < m; i++) {
            p[i] = newp[i * 2 + n % 2];
        }
        for (int i = 0; i <= m; i++) {
            q[i] = newq[i * 2];
        }
        n /= 2;
    }
    return p[0] / q[0];
}

struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;
    
    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    
    void init(int m) {
        if (m <= n) return;
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);
        
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m;
    }
    
    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;

Poly<P> get(int n) {
    if (n == 1) {
        return {0, 1};
    }
    if (n % 2 == 1) {
        auto f = get(n - 1);
        f.resize(n + 1);
        for (int i = n - 1; i >= 0; i--) {
            f[i + 1] += f[i];
            f[i] *= -(n - 1);
        }
        return f;
    }
    auto f = get(n / 2);
    std::vector<Z> pw(n / 2 + 1);
    pw[0] = 1;
    for (int i = 1; i <= n / 2; i++) {
        pw[i] = pw[i - 1] * (-n / 2);
    }
    auto g = Poly<P>(n / 2 + 1,
        [&](int i) {
            return f[i] * comb.fac(i);
        }).mulT(Poly<P>(n / 2 + 1,
            [&](int i) {
                return comb.invfac(i) * pw[i];
            }));
    for (int i = 0; i <= n / 2; i++) {
        g[i] *= comb.invfac(i);
    }
    return f * g;
}

void solve() {
    int k, p;
    std::cin >> k >> p;
    
    Poly<P> f(k * p + 1);
    f[0] = 2;
    for (int i = 0; i <= k * p; i++) {
        f[i] -= comb.invfac(i);
    }
    f = f.inv(k * p + 1);
    for (int i = 0; i <= k * p; i++) {
        f[i] *= comb.fac(i) * 2;
    }
    
    Poly<P> g = get(k);
    for (int i = 0; i <= k; i++) {
        g[i] *= comb.invfac(k);
    }
    int n = 1;
    while (n < k * p + 1) {
        n *= 2;
    }
    g.resize(n);
    dft(g);
    for (int i = 0; i < n; i++) {
        g[i] = power(g[i], p);
    }
    idft(g);
    Z ans = 0;
    for (int i = 0; i <= k * p; i++) {
        ans += f[i] * g[i];
    }
    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t = 1;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 3616kb

input:

3
2 3
1 10
9 6

output:

818
204495126
16726290

result:

ok 3 number(s): "818 204495126 16726290"

Test #2:

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

input:

3
10 1
1 3
1 2

output:

2
26
6

result:

ok 3 number(s): "2 26 6"

Test #3:

score: 0
Accepted
time: 695ms
memory: 3780kb

input:

2112
16 51
27 30
32 22
6 69
1 7
6 40
15 63
23 37
11 57
6 92
8 62
5 50
11 76
1 57
99 8
2 90
35 10
13 54
6 33
8 70
14 48
12 63
7 99
85 7
14 60
7 78
22 22
1 53
6 61
2 67
8 68
5 67
7 57
8 79
11 29
15 44
8 62
19 39
9 71
3 65
3 83
6 16
11 86
7 25
124 6
1 21
5 76
17 35
14 29
1 55
67 13
987 1
8 27
4 99
8 19...

output:

958728366
182850046
337462356
238321759
94586
688819126
880558546
673294800
592760052
772846256
555807947
834237048
258386591
443217990
83210442
741605708
687991731
380324156
884202426
190172937
130140451
931313604
659396498
344165836
434542961
111646504
6836992
571531367
631528990
880394933
1976309...

result:

ok 2112 numbers

Test #4:

score: 0
Accepted
time: 1400ms
memory: 29128kb

input:

6
1 164257
7 10955
1 30358
1 198674
1 206507
1 323519

output:

450748134
285759990
479497879
856048370
75480834
220335166

result:

ok 6 numbers

Test #5:

score: 0
Accepted
time: 1472ms
memory: 62952kb

input:

4
62 12597
13 15082
2 11295
1 330

output:

134578883
817592796
66930551
383110659

result:

ok 4 number(s): "134578883 817592796 66930551 383110659"

Test #6:

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

input:

1009
31 32
25 40
41 24
500 2
29 34
38 26
38 26
90 11
200 5
71 14
50 20
34 29
47 21
125 8
111 9
37 27
142 7
45 22
125 8
27 36
58 17
27 36
35 28
28 35
43 23
125 8
333 3
32 31
71 14
25 39
100 10
35 28
27 36
47 21
27 37
66 15
47 21
25 40
37 27
34 29
45 22
35 28
66 15
333 3
50 20
25 39
25 39
26 38
76 13
...

output:

871402622
419577502
603695744
784359155
759347810
51557094
51557094
712633402
954410959
616922676
816335450
256771489
866916495
760989591
859187268
459975997
550880541
525468303
760989591
277034910
243040669
277034910
631662375
200080307
141253289
760989591
775322262
996562074
616922676
86443311
524...

result:

ok 1009 numbers

Test #7:

score: 0
Accepted
time: 1054ms
memory: 4264kb

input:

208
139 31
117 45
41 41
267 35
82 16
3 45
181 41
1219 8
31 44
1528 5
235 4
222 10
269 26
827 2
870 7
16 23
263 25
11 26
660 15
129 41
141 11
64 36
100 49
122 50
276 27
44 11
128 24
217 37
335 14
24 49
237 39
418 18
48 35
94 33
375 16
4 47
121 39
95 12
858 7
304 31
370 21
182 33
194 15
55 6
202 13
24...

output:

851150545
222205624
161298067
690708886
622565881
900621090
661760377
251742611
60893316
648664643
49553591
112014667
919771321
587648714
771905571
833478149
713320155
677714356
137765434
3585171
981954406
488903479
513181593
874511965
16170849
442603529
950708093
985481603
369032829
887191778
69043...

result:

ok 208 numbers

Test #8:

score: 0
Accepted
time: 1186ms
memory: 63748kb

input:

1
1000 1000

output:

783050993

result:

ok 1 number(s): "783050993"

Test #9:

score: 0
Accepted
time: 122ms
memory: 4144kb

input:

10
100 100
99 101
98 102
97 103
96 104
101 99
102 98
103 97
104 96
105 95

output:

745474847
348955190
781334174
938153402
358565847
695815461
196183578
379968206
129529953
29572094

result:

ok 10 numbers

Test #10:

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

input:

6
3 2
4 4
3 3
3 5
5 3
4 5

output:

126
124014359
32162
328827205
64386506
567277979

result:

ok 6 numbers

Test #11:

score: 0
Accepted
time: 1244ms
memory: 10300kb

input:

10
100 1000
1000 100
250 400
400 250
25000 4
5 20000
10 10000
10000 10
20000 5
4 25000

output:

354756979
228119416
829496936
168882209
168334375
302715191
745862435
202616186
375396996
520541595

result:

ok 10 numbers

Test #12:

score: 0
Accepted
time: 1ms
memory: 3796kb

input:

10
7 7
5 8
10 4
13 2
2 15
3 9
8 8
6 9
5 3
4 10

output:

629286899
91930612
465722397
823378532
871380528
417689043
815208695
887739621
64386506
566247517

result:

ok 10 numbers