#include <bits/stdc++.h>
#define For(i, x, y) for (int i = (x); i <= (y); i ++)
#define sz(v) (int)(v.size())
using namespace std;
int ksm(int x, int y, int p) {
int v = 1; x %= p;
while (y) v = 1ll * v * ((y & 1) ? x : 1) % p, x = 1ll * x * x % p, y >>= 1;
return v % p;
}
namespace Poly {
typedef vector< int > poly;
const int mod = 998244353, G = 3, invG = ksm(3, mod - 2, mod);
vector< int > id;
poly get (poly a, int n) {
a.resize(n, 0);
return a;
}
poly NTT (poly a, int op) {
int n = sz(a);
For (i, 0, n - 1) if (i < id[i]) swap(a[i], a[id[i]]);
for (int k = 1; k < n; k <<= 1) {
int wn = ksm(op == 1 ? G : invG, (mod - 1) / (k << 1), mod);
for (int i = 0; i < n; i += (k << 1)) {
int w = 1;
for (int j = 0; j < k; j ++, w = 1ll * w * wn % mod) {
int x = a[i + j], y = 1ll * w * a[i + j + k] % mod;
a[i + j] = (x + y) % mod; a[i + j + k] = (x - y + mod) % mod;
}
}
}
if (op == -1) {
int val = ksm(n, mod - 2, mod);
For (i, 0, n - 1) a[i] = 1ll * a[i] * val % mod;
}
return a;
}
poly operator * (poly a, poly b) {
int n = sz(a), m = sz(b), k = 0;
while ((1 << k) <= n + m - 2) k ++;
id.resize(1 << k);
For (i, 1, (1 << k) - 1) id[i] = ((id[i >> 1] >> 1) | ((i & 1) << (k - 1)));
a.resize(1 << k, 0); b.resize(1 << k, 0); a = NTT(a, 1); b = NTT(b, 1);
For (i, 0, (1 << k) - 1) a[i] = 1ll * a[i] * b[i] % mod;
a = NTT(a, -1); a.resize(n + m - 1, 0);
return a;
}
poly operator + (poly a, poly b) {
int n = sz(a), m = sz(b); n = max(n, m); a.resize(n, 0); b.resize(n, 0);
For (i, 0, n - 1) a[i] += b[i], (a[i] >= mod) && (a[i] -= mod);
return a;
}
poly operator - (poly a, poly b) {
int n = sz(a), m = sz(b); n = max(n, m); a.resize(n, 0); b.resize(n, 0);
For (i, 0, n - 1) a[i] += mod - b[i], (a[i] >= mod) && (a[i] -= mod);
return a;
}
poly mul (poly a, int v) {
for (int &x : a) x = 1ll * x * v % mod;
return a;
}
poly inv (poly a) {
int n = sz(a);
if (n == 1) return poly{ksm(a[0], mod - 2, mod)};
poly b = inv(get(a, (n + 1) >> 1));
return get(mul(b, 2) - a * b * b, n);
}
poly deriv (poly a) {
int n = sz(a); poly b(n - 1);
For (i, 0, n - 2) b[i] = 1ll * (i + 1) * a[i + 1] % mod;
return b;
}
poly integ (poly a) {
int n = sz(a); poly b(n + 1, 0);
For (i, 1, n) b[i] = 1ll * a[i - 1] * ksm(i, mod - 2, mod) % mod;
return b;
}
poly ln (poly a) {
return integ(get(deriv(a) * inv(a), sz(a) - 1));
}
poly exp (poly a, int n = 0) {
if (sz(a) == 1) return poly{1};
if (!n) n = sz(a);
const poly b = exp(get(a, (sz(a) + 1) >> 1), sz(a));
return get(b * (a - ln(b)) + b, n);
}
poly operator ^ (poly a, int k) {
return exp(mul(ln(a), k));
}
}
using namespace Poly;
int main () {
ios :: sync_with_stdio(0);
cin.tie(0); cout.tie(0);
return 0;
}
标签:sz,return,get,int,多项式,poly,模板,mod
From: https://www.cnblogs.com/lycc2009/p/18508610