Address
- 洛谷 RemoteJudge
- Codeforces 438E
Meaning
- 给定一个 n n n 元正整数集合 S S S
- 对于任意的 1 ≤ i ≤ m 1\le i\le m 1≤i≤m
- 求有多少棵不同(形态不同或点权不同)的点带权无标号有根二叉树的所有点权和为 i i i (所有的点权都在集合 S S S 内)
- 1 ≤ n , m , S 内 的 元 素 ≤ 1 0 5 1\le n,m,S内的元素\le10^5 1≤n,m,S内的元素≤105
Solution
- 先列出 DP 式子: f [ i ] f[i] f[i] 表示点权和为 i i i 的方案数, f [ 0 ] = 1 f[0]=1 f[0]=1
- f [ i ] = ∑ k ∈ S , k ≤ i ∑ j = 0 i − k f [ j ] f [ i − k − j ] f[i]=\sum_{k\in S,k\le i}\sum_{j=0}^{i-k}f[j]f[i-k-j] f[i]=k∈S,k≤i∑j=0∑i−kf[j]f[i−k−j]
- 设 f f f 的生成函数为 F ( x ) F(x) F(x) ,则
- f [ i ] = ∑ k ∈ S , k ≤ i [ x i − k ] F ( x ) 2 f[i]=\sum_{k\in S,k\le i}[x^{i-k}]F(x)^2 f[i]=k∈S,k≤i∑[xi−k]F(x)2
- 再设生成函数
- G ( x ) = ∑ k ∈ S x k G(x)=\sum_{k\in S}x^k G(x)=k∈S∑xk
- 则
- f [ i ] = ∑ k = 1 i [ x k ] G ( x ) [ x i − k ] F ( x ) 2 = [ x i ] G ( x ) F ( x ) 2 f[i]=\sum_{k=1}^i[x^k]G(x)[x^{i-k}]F(x)^2=[x^i]G(x)F(x)^2 f[i]=k=1∑i[xk]G(x)[xi−k]F(x)2=[xi]G(x)F(x)2
- 于是再加上边界条件 f [ 0 ] = 1 f[0]=1 f[0]=1 ,得
- F ( x ) = 1 + G ( x ) F ( x ) 2 F(x)=1+G(x)F(x)^2 F(x)=1+G(x)F(x)2
- 解关于 F ( x ) F(x) F(x) 的一元二次方程得
- F ( x ) = 1 ± 1 − 4 G ( x ) 2 G ( x ) F(x)=\frac{1\pm\sqrt{1-4G(x)}}{2G(x)} F(x)=2G(x)1±1−4G(x)
- 注意到 [ x 0 ] G ( x ) = 0 [x^0]G(x)=0 [x0]G(x)=0 ,所以 G ( x ) − 1 G(x)^{-1} G(x)−1 不存在,当 ± \pm ± 取 + + + 时分子的 0 0 0 次项不为 0 0 0 ,这样显然是没有意义的,所以
- F ( x ) = 1 − 1 − 4 G ( x ) 2 G ( x ) = 2 1 + 1 − 4 G ( x ) F(x)=\frac{1-\sqrt{1-4G(x)}}{2G(x)}=\frac2{1+\sqrt{1-4G(x)}} F(x)=2G(x)1−1−4G(x) =1+1−4G(x) 2
- 使用多项式开平方 + 多项式求逆解决
- 最后科普一下多项式开平方
- 先假设你会多项式求逆
- 考虑和多项式 exp 一样使用牛顿迭代求解
- 大概就是我们要求一个多项式 G ( x ) ≡ F ( x ) (   m o d   x n ) G(x)\equiv \sqrt{F(x)}(\bmod x^n) G(x)≡F(x) (modxn)
- 也就是 G ( x ) 2 − F ( x ) ≡ 0 (   m o d   x n ) G(x)^2-F(x)\equiv 0(\bmod x^n) G(x)2−F(x)≡0(modxn)
- 根据牛顿迭代
- x n + 1 = x n − f ( x ) f ′ ( x ) x_{n+1}=x_n-\frac{f(x)}{f'(x)} xn+1=xn−f′(x)f(x)
- 得到多项式开平方的迭代
- G k + 1 ( x ) = G k ( x ) − G k ( x ) 2 − F ( x ) 2 G k ( x ) G_{k+1}(x)=G_k(x)-\frac{G_k(x)^2-F(x)}{2G_k(x)} Gk+1(x)=Gk(x)−2Gk(x)Gk(x)2−F(x)
- 其中 G k ( x ) G_k(x) Gk(x) 表示 F ( x ) F(x) F(x) 模 x 2 k x^{2^k} x2k 意义下的开平方
- 其中 G 0 ( x ) = [ x 0 ] F ( x ) G_0(x)=\sqrt{[x^0]F(x)} G0(x)=[x0]F(x)
- 迭代到 G k ( x ) G_k(x) Gk(x) 满足 2 k ≥ n 2^k\ge n 2k≥n 时,我们就求得了模 x n x^n xn 的开平方
- 考虑复杂度,对模 x n x^n xn 开平方的复杂度 T ( n ) T(n) T(n) 满足
- T ( n ) = T ( n 2 ) + O ( n log n ) T(n)=T(\frac n2)+O(n\log n) T(n)=T(2n)+O(nlogn)
- T ( n ) = O ( n log n ) T(n)=O(n\log n) T(n)=O(nlogn)
Code
#include
#include
#include
#include
#include
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
#define Pow(k, n) for (k = 1; k < n; k <<= 1)
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
template <class T>
inline void Swap(T &a, T &b) {a ^= b; b ^= a; a ^= b;}
const int N = 14e5 + 5, ZZQ = 998244353;
int n, m, cnt[N], rev[N], ff = 4, tot = 2, gg = 748683265, omega[N],
sqrtc[N], invc[N], tmp[N], invsq[N], pmt[N];
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % ZZQ;
a = 1ll * a * a % ZZQ;
b >>= 1;
}
return res;
}
void FFT(int n, int *a, int op)
{
int i, j, k = n >> 1;
For (i, 0, n - 1) if (i < rev[i]) Swap(a[i], a[rev[i]]);
omega[n] = qpow(3, (ZZQ - 1) / n * (op == 1 ? 1 : n - 1));
while (k)
omega[k] = 1ll * omega[k << 1] * omega[k << 1] % ZZQ, k >>= 1;
Pow(k, n)
{
int x = omega[k << 1];
Step (i, 0, n - 1, k << 1)
{
int w = 1;
For (j, 0, k - 1)
{
int u = a[i + j], v = 1ll * w * a[i + j + k] % ZZQ;
a[i + j] = (u + v) % ZZQ;
a[i + j + k] = (u - v + ZZQ) % ZZQ;
w = 1ll * w * x % ZZQ;
}
}
}
}
void getinv(int n, int *a, int *res)
{
int i, k, ff = 4, gg = 748683265, tot = 2;
res[0] = qpow(a[0], ZZQ - 2);
Pow(k, n)
{
For (i, 0, ff - 1)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << tot - 1);
For (i, 0, (ff >> 1) - 1) pmt[i] = a[i];
For (i, ff >> 1, ff - 1) pmt[i] = 0;
For (i, ff >> 2, ff - 1) res[i] = 0;
FFT(ff, pmt, 1); FFT(ff, res, 1);
For (i, 0, ff - 1)
res[i] = 1ll * res[i] * (2 - 1ll * pmt[i] * res[i] % ZZQ
+ ZZQ) % ZZQ;
FFT(ff, res, -1);
For (i, 0, (ff >> 1) - 1) res[i] = 1ll * res[i] * gg % ZZQ;
ff <<= 1; tot++;
gg = 499122177ll * gg % ZZQ;
}
For (i, n, ff >> 1) res[i] = 0;
}
int main()
{
int i, x, k;
n = read(); m = read();
For (i, 1, n) if ((x = read()) <= m) cnt[x] = ZZQ - 4;
cnt[0] = sqrtc[0] = 1;
Pow(k, m + 1)
{
For (i, 0, k - 1) tmp[i] = sqrtc[i];
For (i, k, (k << 1) - 1) tmp[i] = 0;
getinv(k << 1, tmp, invc);
For (i, 0, ff - 1)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << tot - 1);
For (i, 0, (ff >> 1) - 1) tmp[i] = cnt[i];
For (i, ff >> 1, ff - 1) tmp[i] = 0;
FFT(ff, tmp, 1); FFT(ff, sqrtc, 1); FFT(ff, invc, 1);
For (i, 0, ff - 1)
sqrtc[i] = (sqrtc[i] - 499122177ll *
(1ll * sqrtc[i] * sqrtc[i] % ZZQ - tmp[i] + ZZQ)
% ZZQ * invc[i] % ZZQ + ZZQ) % ZZQ;
FFT(ff, sqrtc, -1);
For (i, 0, (ff >> 1) - 1) sqrtc[i] = 1ll * sqrtc[i] * gg % ZZQ;
For (i, ff >> 1, ff - 1) sqrtc[i] = 0;
ff <<= 1; tot++;
gg = 499122177ll * gg % ZZQ;
}
For (i, m + 1, ff >> 1) sqrtc[i] = 0;
sqrtc[0]++; invsq[0] = 499122177;
getinv(m + 1, sqrtc, invsq);
For (i, 1, m) printf("%d\n", 2 * invsq[i] % ZZQ);
return 0;
}