CF438E The Child and Binary Tree
https://www.luogu.com.cn/problem/CF438E
设
f
i
f_i
fi表示点权和为
i
i
i的合法二叉树个数,
g
i
g_i
gi表示权值为
i
i
i 的点合不合法
显然可以得到
f
n
=
∑
i
=
1
g
i
∑
j
f
j
f
n
−
i
−
j
,
f
0
=
1
f_n=\sum_{i=1}g_i\sum_j f_jf_{n-i-j}, f_0=1
fn=i=1∑gij∑fjfn−i−j,f0=1
写成生成函数就是
F
=
G
F
2
+
1
F=GF^2+1
F=GF2+1
解得
F
=
1
−
1
−
4
G
2
G
F=\frac{1-\sqrt{1-4G}}{2G}
F=2G1−1−4G
分母有理化一下讨论,发现只有一个解是收敛的,舍去另一个得到上式
F
=
2
1
+
1
−
4
G
F=\frac{2}{1+\sqrt{1-4G}}
F=1+1−4G2
冲个开根和求逆即可
code:
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define G 3
#define N 800005
using namespace std;
int qpow(int x, int y){
int ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
int rev[N], G_inv, len_inv;
void ntt(int *a, int len, int o){
len_inv = qpow(len, mod - 2);
for(int i = 0; i <= len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i&1) * len >> 1);
for(int i = 0; i <= len; i ++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i = 2; i <= len; i <<= 1){
int wn = qpow((o == 1)? G:G_inv, (mod - 1) / i);
for(int j = 0, p = i / 2; j + i - 1 <= len; j += i){
int w0 = 1;
for(int k = j; k < j + p; k ++, w0 = w0 * wn % mod){
int X = a[k], Y = w0 * a[k + p] % mod;
a[k] = (X + Y) % mod;
a[k + p] = (X - Y + mod) % mod;
}
}
}
if(o == -1)
for(int i = 0; i <= len; i ++) a[i] = a[i] * len_inv % mod;
}
int c[N];
void inv(int *a, int *b, int sz){
if(sz == 0) {b[0] = qpow(a[0], mod - 2); return;}
inv(a, b, sz / 2);
int len = 1;
for(; len <= sz + sz; len <<= 1);
for(int i = 0; i <= sz; i ++) c[i] = a[i];
for(int i = sz + 1; i <= len; i ++) c[i] = 0;
ntt(c, len, 1), ntt(b, len, 1);
for(int i = 0; i <= len; i ++) b[i] = (b[i] * 2 % mod - b[i] * b[i] % mod * c[i] % mod + mod) % mod;
ntt(b, len, -1);
for(int i = sz + 1; i <= len; i ++) b[i] = 0;
}
void qiudao(int *a, int sz) {
for(int i = 0; i < sz; i ++) a[i] = a[i + 1] * (i + 1) % mod;
a[sz] = 0;
}
void jifen(int *a, int sz) {
for(int i = sz; i >= 1; i --) a[i] = a[i - 1] * qpow(i, mod - 2) % mod;
a[0] = 0;
}
int Ad[N], An[N];
void ln(int *A, int n) {
for(int i = 0; i <= n; i ++) Ad[i] = A[i];
qiudao(Ad, n);
inv(A, An, n);
int len = 1;
for(; len <= n + n;) len <<= 1;
ntt(Ad, len, 1), ntt(An, len, 1);
for(int i = 0; i <= len; i ++) Ad[i] = Ad[i] * An[i] % mod;
ntt(Ad, len, -1);
jifen(Ad, n);
for(int i = 0; i <= n; i ++) A[i] = Ad[i];
for(int i = 0; i <= len; i ++) An[i] = Ad[i] = 0;
}
int fln[N];
void exp(int *a, int *b, int n) {
if(n == 0) {b[0] = 1; return;}
exp(a, b, n / 2);
for(int i = 0; i <= n; i ++) fln[i] = b[i]; ln(fln, n);
fln[0] = 1;
for(int i = 1; i <= n; i ++) fln[i] = (a[i] - fln[i] + mod ) % mod;
int len = 1;
for(; len <= n + n;) len <<= 1;
ntt(b, len, 1), ntt(fln, len, 1);
for(int i = 0; i <= len; i ++) b[i] = b[i] * fln[i] % mod;
ntt(b, len, -1);
for(int i = 0; i <= len; i ++) fln[i] = 0;
}
int a[N], b[N], n, m, fac[N], ifac[N], ib[N];
void init(int n) {
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
}
signed main(){
init(N - 10);
G_inv = qpow(G, mod - 2);
scanf("%lld%lld", &m, &n);
for(int i = 1; i <= m; i ++) {
int x;
scanf("%lld", &x);
a[x] = 1;
}
a[0] = 1;
for(int i = 1; i <= n; i ++) a[i] = (mod - 4 * a[i]);
ln(a, n);
for(int i = 0; i <= n; i ++) a[i] = a[i] * ifac[2] % mod;
exp(a, b, n);
b[0] = (b[0] + 1) % mod;
inv(b, ib, n);
for(int i = 1; i <= n; i ++) printf("%lld\n", ib[i] * 2 % mod);
return 0;
}