1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| const int MAXN = 1 << 20; const int MOD = 998244353; namespace polynomial { inline int add(int x, int y) { return x += y, x >= MOD ? x - MOD : x; } inline int sub(int x, int y) { return x -= y, x < 0 ? x + MOD : x; } inline int qpow(int x, int y, int p = MOD) { int ret = 1; for (; y; y >>= 1, x = 1ll * x * x % p) if (y & 1) ret = 1ll * ret * x % p; return ret; } template <class _Tp> void change(_Tp* f, int len) { static int rev[MAXN] = {}; for (int i = rev[0] = 0; i < len; ++i) { rev[i] = rev[i >> 1] >> 1; if (i & 1) rev[i] |= len >> 1; } for (int i = 0; i < len; ++i) if (i < rev[i]) swap(f[i], f[rev[i]]); } void ntt(int* f, int len, int on) { change(f, len); for (int h = 2; h <= len; h <<= 1) { int gn = qpow(3, (MOD - 1) / h); for (int j = 0; j < len; j += h) { int g = 1; for (int k = j; k < j + h / 2; ++k) { int u = f[k], t = 1ll * g * f[k + h / 2] % MOD; f[k] = add(u, t), f[k + h / 2] = sub(u, t); g = 1ll * g * gn % MOD; } } } if (on == -1) { reverse(f + 1, f + len); int inv = qpow(len, MOD - 2); for (int i = 0; i < len; ++i) f[i] = 1ll * f[i] * inv % MOD; } } int polymul(const int* f, int n, const int* g, int m, int* ans) { static int tf[MAXN] = {}, tg[MAXN] = {}; int len = 1; while (len < n + m - 1) len <<= 1; copy(f, f + n, tf), fill(tf + n, tf + len, 0); copy(g, g + m, tg), fill(tg + m, tg + len, 0); ntt(tf, len, 1), ntt(tg, len, 1); for (int i = 0; i < len; ++i) tf[i] = 1ll * tf[i] * tg[i] % MOD; ntt(tf, len, -1); copy(tf, tf + n + m - 1, ans); return n + m - 1; } int polyinv(const int* f, int n, int* ans) { static int tmp[MAXN] = {}; int len = 1; while (len < n) len <<= 1; fill(ans, ans + len + len, 0); ans[0] = qpow(f[0], MOD - 2); for (int h = 2; h <= len; h <<= 1) { copy(f, f + h, tmp); fill(tmp + h, tmp + h + h, 0); ntt(tmp, h + h, 1), ntt(ans, h + h, 1); for (int i = 0; i < h + h; ++i) ans[i] = 1ll * ans[i] * (2 - 1ll * ans[i] * tmp[i] % MOD + MOD) % MOD; ntt(ans, h + h, -1), fill(ans + h, ans + h + h, 0); } return n; } int derivation(const int* f, int n, int* ans) { for (int i = 0; i < n - 1; ++i) ans[i] = 1ll * f[i + 1] * (i + 1) % MOD; return ans[n - 1] = 0, n - 1; } int integral(const int* f, int n, int* ans) { for (int i = n; i >= 1; --i) ans[i] = 1ll * f[i - 1] * qpow(i, MOD - 2) % MOD; return ans[0] = 0, n + 1; } int ln(const int* f, int n, int* ans) { static int tf[MAXN] = {}, tg[MAXN] = {}; derivation(f, n, tf); polyinv(f, n, tg); polymul(tf, n - 1, tg, n, ans); integral(ans, n - 1, ans); fill(ans + n, ans + n + n, 0); return n; } int exp(const int* f, int n, int* ans) { static int tmp[MAXN] = {}; ans[0] = 1, ans[1] = 0; for (int h = 2; h <= (n << 1); h <<= 1) { ln(ans, h, tmp); for (int i = 0; i < h; ++i) tmp[i] = add(i == 0, sub(f[i], tmp[i])); polymul(ans, h, tmp, h, ans); } return n; } }; using namespace polynomial;
|