BZOJ 3625: [Codeforces Round #250]小朋友和二叉树

3625: [Codeforces Round #250]小朋友和二叉树

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 304  Solved: 130
[Submit][Status][Discuss]

Description

我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],...,c[n]}中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
给出一个整数m,你能对于任意的s(1<=s<=m)计算出权值为s的神犇二叉树的个数吗?请参照样例以更好的理解什么样的两棵二叉树会被视为不同的。
我们只需要知道答案关于998244353(7*17*2^23+1,一个质数)取模后的值。

Input

第一行有2个整数 n,m(1<=n<=10^5; 1<=m<=10^5)。
第二行有n个用空格隔开的互异的整数 c[1],c[2],...,c[n](1<=c[i]<=10^5)。

Output

输出m行,每行有一个整数。第i行应当含有权值恰为i的神犇二叉树的总数。请输出答案关于998244353(=7*17*2^23+1,一个质数)取模后的结果。

Sample Input

样例一:
2 3
1 2
样例二:
3 10
9 4 3
样例三:
5 10
13 10 6 4 15

Sample Output

样例一:
1
3
9
样例二:
0
0
1
1
0
2
4
2
6
15
样例三:
0
0
0
1
0
1
0
2
0
5

HINT

 

对于第一个样例,有9个权值恰好为3的神犇二叉树:

 

Source

[Submit][Status][Discuss]

 

据说是道生成函数+多项式计算水题,所以机房里只有我这样的蒟蒻才不会做。

设F(x)中的i次方项系数表示权值和为i的二叉树的个数。(这个就是最终答案函数)

设C(x)中的i次方项系数表示权值i是否出现在可选集合内。(这其实就是C集合的bitset表示)

然后得到$F=CF^2+1$,其中C为枚举根节点权值,两个F分别是左右子树,+1代表可能是一棵空树。

化简得到$CF^2-F+1=0$,根据一元二次方程求根公式,这个多项式方程的根就是$\frac{1\pm\sqrt{1-4C}}{2C}$。

然后嘞,就支持一下多项式开方,多项式求逆好了,其中需要用到NTT和两个倍增算法,然而蒟蒻的我并不会,只好向Monster_Yi大佬和LincHpin大爷虚心请教。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 template <class T>
  5 inline void read(T &x)
  6 {
  7     x = 0;
  8     char c = getchar();
  9     while (c < 48)c = getchar();
 10     while (c > 47)x = x*10 + c - 48, c = getchar();
 11 }
 12 
 13 template <class T>
 14 inline void swap(T &a, T &b)
 15 {
 16     T c;
 17     c = a;
 18     a = b;
 19     b = c;
 20 }
 21 
 22 const int P = 998244353;
 23 const int D = 499122177;
 24 const int N = 550000;
 25 
 26 inline int pow(int a, int b)
 27 {
 28     int r = 1;
 29     
 30     while (b)
 31     {
 32         if (b & 1)
 33             r = 1LL * r * a % P;
 34         
 35         b >>= 1, a = 1LL * a * a % P;
 36     }
 37     
 38     return r;
 39 }
 40 
 41 inline void ntt(int *a, int len, int type)
 42 {
 43     for (int i = 0, t = 0; i < len; ++i)
 44     {
 45         if (i > t)swap(a[i], a[t]);
 46         for (int j = (len >> 1); (t ^= j) < j; j >>= 1);
 47     }
 48     
 49     for (int h = 2; h <= len; h <<= 1)
 50     {
 51         int wn = pow(5, (P - 1) / h);
 52         
 53         for (int i = 0; i < len; i += h)
 54         {
 55             int wk = 1;
 56             
 57             for (int j = 0; j < (h >> 1); ++j, wk = 1LL * wk * wn % P)
 58             {
 59                 int t = 1LL * wk * a[i + j + (h >> 1)] % P;
 60                 
 61                 a[i + j + (h >> 1)] = (a[i + j] - t + P) % P;
 62                 a[i + j] = (a[i + j] + t) % P;
 63             }
 64         }
 65     }
 66     
 67     if (type == -1)
 68     {
 69         for (int i = 1; i < (len >> 1); ++i)
 70             swap(a[i], a[len - i]);
 71         
 72         int inv = pow(len, P - 2);
 73         
 74         for (int i = 0; i < len; ++i)
 75             a[i] = 1LL * a[i] * inv % P;
 76     }
 77 }
 78 
 79 void inv(int *a, int *b, int len)
 80 {
 81     if (len == 1)
 82         b[0] = pow(a[0], P - 2);
 83     else
 84     {
 85         static int t[N];
 86         
 87         inv(a, b, len >> 1);
 88         
 89         memcpy(t,         a, len * sizeof(int));
 90         memset(t + len,    0, len * sizeof(int));
 91         
 92         ntt(t, len << 1, 1);
 93         ntt(b, len << 1, 1);
 94         
 95         for (int i = 0; i < len << 1; ++i)
 96             b[i] = 1LL * b[i] * (2 - 1LL * t[i] * b[i] % P + P) % P;
 97     
 98         ntt(b, len << 1, -1);
 99         
100         memset(b + len,    0, len * sizeof(int));
101     }
102 }
103 
104 void sqrt(int *a, int *b, int len)
105 {
106     if (len == 1)
107         b[0] = 1;
108     else
109     {
110         static int c[N], d[N];
111         
112         sqrt(a, b, len >> 1);
113         
114         memset(d,        0, len * sizeof(int));
115         memset(d + len, 0, len * sizeof(int));
116         
117         inv(b, d, len);
118         
119         memcpy(c,         a, len * sizeof(int));
120         memset(c + len, 0, len * sizeof(int));
121         
122         ntt(c, len << 1, 1);
123         ntt(b, len << 1, 1);
124         ntt(d, len << 1, 1);
125         
126         for (int i = 0; i < len << 1; ++i)
127             b[i] = (1LL * c[i] * d[i] % P + b[i]) % P * D % P;
128             
129         ntt(b, len << 1, -1);
130         
131         memset(b + len, 0, len * sizeof(int));
132     }
133 }
134 
135 int n, m, len;
136 
137 int a[N], b[N];
138 
139 signed main(void)
140 {
141     read(n);
142     read(m);
143 
144     a[0] = 1;
145 
146     for (len = 1; len <= m; len <<= 1);
147     
148     for (int i = 1, x; i <= n; ++i)
149         if (read(x), x <= m)a[x] = P - 4;
150     
151     sqrt(a, b, len);
152     
153     memcpy(a, b, len * sizeof(int)), ++a[0];
154     memset(b, 0, len * sizeof(int)), inv(a, b, len);
155     memcpy(a, b, len * sizeof(int));
156     
157     for (int i = 1; i <= m; ++i)
158         printf("%d\n", (a[i] << 1) % P);
159 }

 

@Author: YouSiki

 

posted @ 2017-02-21 21:06  YouSiki  阅读(509)  评论(0编辑  收藏  举报