我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有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,一个质数)取模后的值。
第一行有2个整数 n,m(1<=n<=10^5; 1<=m<=10^5)。
第二行有n个用空格隔开的互异的整数 c[1],c[2],...,c[n](1<=c[i]<=10^5)。
输出m行,每行有一个整数。第i行应当含有权值恰为i的神犇二叉树的总数。请输出答案关于998244353(=7*17*2^23+1,一个质数)取模后的结果。
然后嘞,就支持一下多项式开方,多项式求逆好了,其中需要用到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 }