逐点牛顿迭代法
可以在 \(O(n^22^n)\) 的复杂度内解决 \(\sum_i a_i F^i(x)\)
其中卷积是子集卷积, \(F(x)\) 是集合幂级数
做法是设 \(dp_{i, j, s}\) 表示考虑了前 \(i\) 个位置, 还需要选择 \(j\) 个子集, 目前已经选择的集合是 \(s\)
转移是 \(dp_{i, j, s} = dp_{i - 1, j, s} + \sum_{t \subseteq s} [i \in t] dp_{i - 1, j + 1, s/t} f_t\)
后边的卷积使用 FWT 做到 \(i^22^i\)
总的复杂度是 \(\sum_{i=0}^n i^2(n-i)2^i = O(n^22^n)\) 复杂度证明可以直接把 \(i^2\) 近似成 \(n^2\) 后边这个东西使用错位相减求和算出来是 \(2^{n + 1}\) 的
非常厉害, 可以解决几乎全部的内容, ln, exp, 快速幂, 求逆, 只需要使用泰勒展开一下就可以了
但是常数可能会略大, 贴一个模板
namespace FWT {
void OR (int *f, int flag, int len) {
for (int k = 1, o = 2; o <= len; o <<= 1, k <<= 1)
for (int i = 0; i < len; i += o)
for (int j = 0; j < k; j++) {
if (flag) f[i + j + k] = add(f[i + j + k], f[i + j]);
else f[i + j + k] = sub(f[i + j + k], f[i + j]);
}
}
int f[N][S], g[N][S], h[N][S], dp[N + 1][S];
void Main (int *A, int *F, int _) {
for (int i = 0; i <= _; i++)
dp[i][0] = 1ll * A[i] * fac[i] % mod;
for (int i = 1, len = 1; i <= _; i++, len <<= 1) {
for (int s = 0; s < len; s++) g[pc[s]][s] = F[s | len];
for (int k = 0; k < i; k++) OR(g[k], 1, len);
for (int j = 0; j <= _ - i; j++) {
for (int s = 0; s < len; s++) f[pc[s]][s] = dp[j + 1][s];
for (int k = 0; k < i; k++) OR(f[k], 1, len);
for (int t = 0; t < i; t++)
for (int x = 0; x <= t; x++)
for (int s = 0; s < len; s++)
h[t][s] = add(h[t][s], 1ll * f[x][s] * g[t - x][s] % mod);
for (int k = 0; k < i; k++) OR(h[k], 0, len);
for (int s = 0; s < len; s++) dp[j][s | len] = h[pc[s]][s];
for (int k = 0; k < i; k++)
for (int s = 0; s < len; s++)
h[k][s] = f[k][s] = 0;
}
for (int k = 0; k < i; k++)
for (int s = 0; s < len; s++) g[k][s] = 0;
}
}
}

浙公网安备 33010602011771号