voidInit(){ // 在程序开始调用 for (int m = 1; m < MAX_LEN; m <<= 1) { int w = qpow(G, (P - 1) / (m << 1)); omega[m] = 1; for (int i = 1; i < m; ++i) { omega[m + i] = mul(omega[m + i - 1], w); } } inv[1] = 1; for (int i = 2; i < MAX_LEN; ++i) { inv[i] = mul(P - P / i, inv[P % i]); } }
intget(int _n){ int n = 1; while (n < _n) { n <<= 1; } return n; }
voidinit(int n){ int k = 0; while ((1 << k) < n) { ++k; } rev.resize(n), rev[0] = 0, --k; for (int i = 1; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << k); } }
voidDFT(poly &f, int n){ f.resize(n); staticunsignedlonglong F[MAX_LEN]; for (int i = 0; i < n; ++i) { F[rev[i]] = f[i]; } for (int m = 1; m < n; m <<= 1) { // 注意当 MAX_LEN > 2^18 时这里需要把 F[i] 全部模 P for (int p = 0, l = m << 1; p < n; p += l) { int *W = omega + m; unsignedlonglong *F0 = F + p, *F1 = F0 + m; for (int i = 0; i < m; ++i, ++F0, ++F1, ++W) { int t = (*F1) * (*W) % P; *F1 = *F0 + P - t, *F0 += t; } } } for (int i = 0; i < n; ++i) { f[i] = (F[i] % P + P) % P; } }
voidIDFT(poly &f, int n){ DFT(f, n), std::reverse(f.begin() + 1, f.end()); int t = qpow(n, P - 2); for (int i = 0; i < n; ++i) { f[i] = mul(f[i], t); } }
多项式加法与减法
对于每个 \(x_i\) 的系数直接相加/相减即可。
时间复杂度 \(O(n)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
poly Plus(poly a, poly b){ int n = std::max(a.size(), b.size()); a.resize(n), b.resize(n); for (int i = 0; i < n; ++i) { inc(a[i], b[i]); } return a; }
poly Minus(poly a, poly b){ int n = std::max(a.size(), b.size()); a.resize(n), b.resize(n); for (int i = 0; i < n; ++i) { dec(a[i], b[i]); } return a; }
多项式乘法
DFT 后把点值乘起来,在 IDFT 回去即可。
代码中的参数 _n 的作用在下面会提到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
poly Mul(poly a, poly b, int _n = -1){ int na = (int)a.size(), nb = (int)b.size(), n = _n; if (!na || !nb || !n) { return {}; } if (n == -1) { n = na + nb - 1; } _n = n, n = get(n); init(n), DFT(a, n), DFT(b, n); for (int i = 0; i < n; ++i) { a[i] = mul(a[i], b[i]); } IDFT(a, n); a.resize(_n); return a; }
可以把计算 \(F^2(x)\) 单独写一个函数,常数可以更小。
1 2 3 4 5 6 7 8 9 10 11
poly Pow2(poly a){ int _n = 2 * (int)a.size() - 1; int n = get(_n); init(n), DFT(a, n); for (int i = 0; i < n; ++i) { a[i] = mul(a[i], a[i]); } IDFT(a, n); a.resize(_n); return a; }
poly ExpNewton(poly f, int _n){ int n = get(_n); f.resize(n); poly g(1); g[0] = 1; for (int m = 2; m <= n; m <<= 1) { int l = m << 1; poly tmp = Ln(g, m); for (int i = 0; i < m; ++i) { tmp[i] = minus(f[i], tmp[i]); } inc(tmp[0], 1); init(l), DFT(tmp, l), DFT(g, l); for (int i = 0; i < l; ++i) { g[i] = mul(g[i], tmp[i]); } IDFT(g, l), g.resize(m); } return g.resize(_n), g; }
poly Pow(poly a, int k, int n){ a.resize(n); int t = n; for (int i = 0; i < n; ++i) { if (a[i]) { t = i; break; } } if (t == n) { if (!k) { a[0] = 1; } return a; } int vi = qpow(a[t], P - 2), vk = qpow(a[t], k); for (int i = 0; i < n - t; ++i) { a[i] = mul(a[i + t], vi); } a.resize(n - t); t = std::min(1ll * t * k, 1ll * n); if (t == n) { a.resize(n); for (int i = 0; i < n; ++i) { a[i] = 0; } return a; } a = Ln(a, n - t); for (int i = 0; i < n - t; ++i) { a[i] = mul(a[i], k); } a = Exp(a, n - t), a.resize(n); for (int i = n - t - 1; ~i; --i) { a[i + t] = mul(a[i], vk); } for (int i = 0; i < t; ++i) { a[i] = 0; } return a; }
poly Sqrt(poly f, int _n){ int n = get(_n); f.resize(n); poly g(1); g[0] = Sqrt(f[0]); // 求二次剩余 for (registerint m = 2; m <= n; m <<= 1){ poly tmp = Pow2(g); tmp.resize(m); for (registerint i = 0; i < m; ++i) inc(tmp[i], f[i]); g = Multiply(tmp, Inverse(g, m)), g.resize(m); for (registerint i = 0; i < m; ++i) g[i] = mul(g[i], inv[2]); } return g.resize(_n), g; }
voidInit(){ for (int m = 1; m < MAX_LEN; m <<= 1) { for (int i = 0; i < m; ++i) { omega[m + i] = {cos(pi / m * i), sin(pi / m * i)}; } } }
intget(int _n){ int n = 1; while (n < _n) { n <<= 1; } return n; }
std::vector<int> rev;
voidinit(int n){ int k = 0; while ((1 << k) < n) { ++k; } rev.resize(n), rev[0] = 0, --k; for (int i = 1; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << k); } }
voidDFT(std::vector<Complex> &f, int n){ f.resize(n); static Complex F[MAX_LEN]; for (int i = 0; i < n; ++i) { F[rev[i]] = f[i]; } for (int m = 1; m < n; m <<= 1) { for (int p = 0; p < n; p += m << 1) { Complex *W = omega + m; Complex *F0 = F + p, *F1 = F0 + m; for (int i = 0; i < m; ++i, ++W, ++F0, ++F1) { Complex t = (*F1) * (*W); *F1 = *F0 - t, *F0 = *F0 + t; } } } for (int i = 0; i < n; ++i) { f[i] = F[i]; } }
voidIDFT(std::vector<Complex> &f, int n){ DFT(f, n), std::reverse(f.begin() + 1, f.end()); for (int i = 0; i < n; ++i) { f[i] = f[i] * (Complex){1.0 / n, 0}; } }
poly Mul(const poly &f, const poly &g, int P){ int fn = f.size(), gn = g.size(), _n = fn + gn - 1; std::vector<Complex> fa(fn), fb(fn), ga(gn), gb(gn); for (int i = 0; i < fn; ++i) { fa[i].x = f[i] >> 15, fa[i].y = 0; fb[i].x = f[i] & 32767, fb[i].y = 0; } for (int i = 0; i < gn; ++i) { ga[i].x = g[i] >> 15, ga[i].y = 0; gb[i].x = g[i] & 32767, gb[i].y = 0; } int n = get(_n); init(n), DFT(fa, n), DFT(fb, n), DFT(ga, n), DFT(gb, n); std::vector<Complex> a(n), b(n), c(n); for (int i = 0; i < n; ++i) { a[i] = fa[i] * ga[i]; b[i] = fa[i] * gb[i] + fb[i] * ga[i]; c[i] = fb[i] * gb[i]; } IDFT(a, n), IDFT(b, n), IDFT(c, n); poly ans(_n); for (int i = 0; i < _n; ++i) { longlong A = a[i].x + 0.5, B = b[i].x + 0.5, C = c[i].x + 0.5; A %= P, B %= P, C %= P; ans[i] = ((1 << 30) * A + (1 << 15) * B + C) % P; ans[i] = (P + ans[i]) % P; } return ans; } }