Codeforces 438E The Child and Binary Tree - 生成函数 - 多项式

题目传送门

  传送点I

  传送点II

  传送点III

题目大意

  每个点的权值$c\in {c_{1}, c_{2}, \cdots, c_{n}}$,问对于每个$1\leqslant s\leqslant 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)$平方就能得到$f\otimes f$的生成函数。我们用它替换右半边,得到了:

$F(x) = \sum_{c \in C}x^{c}F^2(x) + 1$

  设某个常数$A = \sum_{c \in C}x^{c}$,则有$A\cdot 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)}{2A\sqrt{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\n", add(C[i], C[i]));
155 }
156 
157 int main() {
158     init();
159     solve();
160     return 0;
161 }
posted @ 2018-09-30 08:12  阿波罗2003  阅读(312)  评论(0编辑  收藏  举报