题目传送门
题目大意
每个点的权值$cin {c_{1}, c_{2}, cdots, c_{n}}$,问对于每个$1leqslant sleqslant m$有多少种不同的这样的有根二叉树满足所有点的点权和等于$s$。
先考虑一下怎么用dp来做。
设$f_{n}$表示点权和为$n$的满足条件的二叉树的个数,那么有:
$f_{n} = sum_{c in C}sum_{i = 0}^{n - c}f_{i}f_{n - c - i}$
初值满足$f_{0} = 1$。
注意到右边的式子有点像卷积,考虑$f_{n}$的普通生成函数$F(x) = sum_{n = 0}f_{n}x^{n}$。
将$F(x)$平方就能得到$fotimes f$的生成函数。我们用它替换右半边,得到了:
$F(x) = sum_{c in C}x^{c}F^2(x) + 1$
设某个常数$A = sum_{c in C}x^{c}$,则有$Acdot F^2(x) - F(x) + 1$。
解得$F_{1}(x) = frac{1 + sqrt{1 - 4A}}{2A}, F_{2}(x) = frac{1 - sqrt{1 - 4A}}{2A} = frac{1 - (1 - 4A)}{2Asqrt{1 + 4A}} = frac{2}{sqrt{1 + 4A}}$。
我们考虑$F_{1}(x)$的分母的常数项,它是2,分子的常数项为0,然后求逆的时候就会出事情。
但是$F_{2}(x)$可以通过恒等变换使得分母的常数项为非0。
然后做一次多项式开根,一次多项式求逆就做完了。
Code
1 /** 2 * Codeforces 3 * Problem#438E 4 * Accepted 5 * Time: 1091ms 6 * Memory: 5100k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 262144; 13 const int bzmax = 20; 14 const int M = 998244353; 15 const int g = 3; 16 const int inv2 = (M + 1) >> 1; 17 18 int qpow(int a, int p) { 19 if (p < 0) 20 p += M - 1; 21 int rt = 1, pa = a; 22 for ( ; p; p >>= 1, pa = pa * 1ll * pa % M) 23 if (p & 1) 24 rt = rt * 1ll * pa % M; 25 return rt; 26 } 27 28 int add(int a, int b) { 29 return ((a += b) >= M) ? (a - M) : (a); 30 } 31 32 int sub(int a, int b) { 33 return ((a -= b) < 0) ? (a + M) : (a); 34 } 35 36 class NTT { 37 public: 38 int gn[bzmax], _gn[bzmax]; 39 40 NTT() { 41 for (int i = 0, L = 2; i < bzmax; i++, L <<= 1) { 42 gn[i] = qpow(g, (M - 1) / L); 43 _gn[i] = qpow(g, -(M - 1) / L); 44 } 45 } 46 47 void operator () (int* f, int len, int sgn) { 48 for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) { 49 if (i < j) 50 swap(f[i], f[j]); 51 for (k = len >> 1; j >= k; j -= k, k >>= 1); 52 } 53 54 for (int b = 2, t = 0; b <= len; b <<= 1, t++) { 55 int wn = ((sgn > 0) ? (gn[t]) : (_gn[t])), w = 1, hb = b >> 1; 56 for (int i = 0; i < len; i += b, w = 1) 57 for (int j = i; j < i + hb; j++, w = w * 1ll * wn % M) { 58 int a = f[j], b = f[j + hb] * 1ll * w % M; 59 f[j] = add(a, b); 60 f[j + hb] = sub(a, b); 61 } 62 } 63 64 if (sgn < 0) { 65 int invlen = qpow(len, -1); 66 for (int i = 0; i < len; i++) 67 f[i] = f[i] * 1ll * invlen % M; 68 } 69 } 70 71 int correctLen(int n) { 72 int m = 1; 73 while (m < n) m <<= 1; 74 return m; 75 } 76 }NTT; 77 78 template<typename T> 79 void pcopy(T* ns, T* ne, const T* os) { 80 for ( ; ns != ne; *ns = *os, ns++, os++); 81 } 82 83 template<typename T> 84 void pfill(T* ps, T* pt, T val) { 85 for ( ; ps != pt; *ps = val, ps++); 86 } 87 88 void debug(const int* f, int n) { 89 for (int i = 0; i < n; i++) 90 cerr << f[i] << " "; 91 cerr << endl; 92 } 93 94 void pol_inverse(int *f, int *g, int n) { 95 static int h[N]; 96 if (n == 1) 97 g[0] = qpow(f[0], -1); 98 else { 99 pol_inverse(f, g, (n + 1) >> 1); 100 101 int t = NTT.correctLen(n << 1 | 1); 102 pcopy(h, h + n, f); 103 pfill(h + n, h + t, 0); 104 NTT(h, t, 1); 105 NTT(g, t, 1); 106 for (int i = 0; i < t; i++) 107 g[i] = g[i] * 1ll * sub(2, g[i] * 1ll * h[i] % M) % M; 108 NTT(g, t, -1); 109 pfill(g + n, g + t, 0); 110 } 111 } 112 113 void pol_sqrt(int *f, int *g, int n) { 114 static int C[N], D[N]; 115 if (n == 1) 116 g[0] = 1; 117 else { 118 pol_sqrt(f, g, (n + 1) >> 1); 119 120 int t = NTT.correctLen(n << 1); 121 pcopy(C, C + n, f); 122 pfill(C + n, C + t, 0); 123 pfill(D, D + t, 0); 124 pol_inverse(g, D, n); 125 NTT(C, t, 1); 126 NTT(D, t, 1); 127 NTT(g, t, 1); 128 for (int i = 0; i < t; i++) 129 g[i] = add(C[i] * 1ll * D[i] % M, g[i]) * 1ll * inv2 % M; 130 NTT(g, t, -1); 131 pfill(g + n, g + t, 0); 132 } 133 } 134 135 int n, m; 136 int C[N], qC[N]; 137 138 inline void init() { 139 scanf("%d%d", &n, &m); 140 for (int i = 1, x; i <= n; i++) { 141 scanf("%d", &x); 142 if (x <= m) 143 C[x] = -4; 144 } 145 } 146 147 inline void solve() { 148 C[0]++, m++; 149 pol_sqrt(C, qC, m); 150 qC[0]++; 151 pfill(C, C + m, 0); 152 pol_inverse(qC, C, m); 153 for (int i = 1; i < m; i++) 154 printf("%d ", add(C[i], C[i])); 155 } 156 157 int main() { 158 init(); 159 solve(); 160 return 0; 161 }