题目链接:传送门
我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有n个互异正整数的序列
c
[
1
]
,
c
[
2
]
,
.
.
.
,
c
[
n
]
c[1],c[2],...,c[n]
c[1],c[2],...,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合
c
[
1
]
,
c
[
2
]
,
.
.
.
,
c
[
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
,
一
个
质
数
)
998244353(7*17*2^{23}+1,一个质数)
998244353(7∗17∗223+1,一个质数)取模后的值。
生成函数简介:传送门
令
v
k
v_k
vk表示是否存在一个
i
i
i,满足
c
[
i
]
=
k
c[i]=k
c[i]=k。令
v
v
v的生成函数
V
=
∑
i
=
0
m
v
i
x
i
V=\sum_{i=0}^{m}v_ix^i
V=∑i=0mvixi,其中
v
i
为
0
/
1
v_i为0/1
vi为0/1
令
f
k
f_k
fk表示权值为
k
k
k的二叉树的数量,规定
f
0
=
1
f_0=1
f0=1。令
f
f
f的生成函数
F
=
∑
i
=
0
m
f
i
x
i
F=\sum_{i=0}^{m}f_ix^i
F=∑i=0mfixi。
考虑用
v
v
v推出
f
f
f,不妨枚举根节点的权值,然后计算左右孩子的情况数,即:
f
k
=
∑
i
=
0
k
v
i
∑
j
=
0
k
−
i
f
j
f
k
−
i
−
j
f_k=\sum_{i=0}^{k}v_i\sum_{j=0}^{k-i}f_jf_{k-i-j}
fk=∑i=0kvi∑j=0k−ifjfk−i−j。(枚举根节点的权值
i
i
i,计算左右孩子的情况数,因为规定
f
0
=
1
f_0=1
f0=1,所以允许左右孩子为空)
用
V
,
F
V,F
V,F表示,即
F
(
x
)
=
V
(
x
)
∗
F
2
(
x
)
+
1
F(x)=V(x)*F^2(x)+1
F(x)=V(x)∗F2(x)+1(因为
f
0
=
1
f_0=1
f0=1,所以常数项要+1)
解一元二次方程,得
F
(
x
)
=
1
+
1
−
4
V
(
x
)
2
V
(
x
)
或
1
−
1
−
4
V
(
x
)
2
V
(
x
)
F(x)=\large\frac{1+\sqrt{1-4V(x)}}{2V(x)}或\frac{1-\sqrt{1-4V(x)}}{2V(x)}
F(x)=2V(x)1+1−4V(x)或2V(x)1−1−4V(x)
因为
f
0
=
1
f_0=1
f0=1,所以
F
(
x
)
F(x)
F(x)的常数项应为
1
1
1。
若
F
(
x
)
=
1
+
1
−
4
V
(
x
)
2
V
(
x
)
F(x)=\large\frac{1+\sqrt{1-4V(x)}}{2V(x)}
F(x)=2V(x)1+1−4V(x),则当
x
→
0
x\to{0}
x→0 时,
F
(
x
)
→
1
+
1
0
=
+
∞
F(x)\to\large\frac{1+1}{0}=\normalsize+\infin
F(x)→01+1=+∞,舍去(
l
i
m
lim
lim打不出来……致习)
若
F
(
x
)
=
1
−
1
−
4
V
(
x
)
2
V
(
x
)
F(x)=\large\frac{1-\sqrt{1-4V(x)}}{2V(x)}
F(x)=2V(x)1−1−4V(x),则当
x
→
0
x\to{0}
x→0 时,
F
(
x
)
→
1
F(x)\to1
F(x)→1,成立。
分子有理化,
F
(
x
)
=
1
−
1
−
4
V
(
x
)
2
V
(
x
)
=
2
1
+
1
−
4
V
(
x
)
F(x)=\large\frac{1-\sqrt{1-4V(x)}}{2V(x)}=\frac{2}{1+\sqrt{1-4V(x)}}
F(x)=2V(x)1−1−4V(x)=1+1−4V(x)2,然后搞一下多项式开根+求逆即珂。
Ps.式子中的+1是指常数项+1……差点被孙到
毒瘤代码
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
#define mod 998244353
#define G 3
#define inv2 499122177
#define invG 332748118
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int fpow(int b,int p) {
int ans=1;
while(p) {
if(p&1) ans=(ll)ans*b%mod;
b=(ll)b*b%mod;
p>>=1;
}
return ans;
}
inline int inv(int x) {
return fpow(x,mod-2);
}
const int Size=4000005;
const int INF=0x3f3f3f3f;
int R[Size];
void NTT(int *a,int n,int type) {
for(re i=0; i<n; i++) {
if(i<R[i]) {
swap(a[i],a[R[i]]);
}
}
for(re i=1; i<n; i<<=1) {
ll gn=fpow(type==1?G:invG,(mod-1)/(i<<1));
for(re j=0; j<n; j+=i<<1) {
ll g=1;
for(re k=0; k<i; k++) {
ll x=a[j+k],y=g*a[i+j+k]%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
g=g*gn%mod;
}
}
}
if(type==-1) {
ll iv=inv(n);
for(re i=0; i<n; i++) {
a[i]=(ll)a[i]*iv%mod;
}
}
}
int A[Size],B[Size],ans[Size];
void Inv(int *a,int *b,int n) { //求a的逆
b[0]=inv(a[0]);
int len;
for(len=1; len<(n<<1); len<<=1) {
int lim=len<<1;
for(re i=0; i<len; i++) {
A[i]=a[i];
B[i]=b[i];
}
for(re i=0; i<lim; i++) {
R[i]=(R[i>>1]>>1)|((i&1)*len);
}
NTT(A,lim,1);
NTT(B,lim,1);
for(re i=0; i<lim; i++) {
b[i]=(ll)B[i]*(2ll-(ll)A[i]*B[i]%mod+mod)%mod;
}
NTT(b,lim,-1);
for(re i=len; i<lim; i++) {
b[i]=0;
}
}
for(re i=0; i<len; i++) A[i]=B[i]=0;
for(re i=n; i<len; i++) b[i]=0;
}
void mul(int *a,int *b,int *c,int n) {
int now=1,L=0;
while(now<(n<<1)) {
now<<=1;
L++;
}
for(re i=0; i<now; i++) {
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
}
NTT(a,now,1);
NTT(b,now,1);
for(re i=0; i<now; i++) {
c[i]=(ll)a[i]*b[i]%mod;
}
NTT(c,now,-1);
}
int tmpa[Size],tmpb[Size],tmpc[Size];
void Sqrt(int *a,int *b,int n) {
b[0]=1;
int len;
for(len=1; len<(n<<1); len<<=1) {
int lim=len<<1;
for(re i=0; i<len; i++) {
tmpa[i]=a[i];
}
for(re i=0; i<lim; i++) {
R[i]=(R[i>>1]>>1)|((i&1)*len);
}
Inv(b,tmpb,len);
mul(tmpa,tmpb,tmpc,lim);
for(re i=0; i<lim; i++) {
b[i]=(ll)(b[i]+tmpc[i])*inv2%mod;
}
for(re i=len; i<lim; i++) {
b[i]=0;
}
}
for(re i=0; i<len; i++) tmpa[i]=tmpb[i]=tmpc[i]=0;
for(re i=n; i<len; i++) b[i]=0;
}
int n,m,a[Size],F[Size];
int main() {
n=read();
m=read();
for(re i=0; i<n; i++) {
int x=read();
a[x]=mod-4;
}
a[0]=1;
Sqrt(a,ans,m+1);
ans[0]++;
Inv(ans,F,m+1);
for(re i=1; i<=m; i++) {
printf("%d\n",(ll)F[i]*2%mod);
}
return 0;
}