链接:http://codeforces.com/contest/438/problem/E
题意:给出n个不同的权值
ci(0<ci<=105)
,为不完全二叉树每个节点赋一个值,问子树和为1~m的二叉树有多少种。m,n<=100000
分析:首先,令
F[i]
为所求答案,列出递推式
F[t]=∑i=1n∑j=0t−c[i]F[j]∗F[t−c[i]−j]
右侧很明显是一个卷积,但考虑到n有 105 ,我们需要把c[i]转化成生成函数求解,令 G(x)=∑ni=1xc[i] , F(x)=∑∞i=0F[i]∗xi ,那么有
F(x)=G(x)∗F(x)2+1
最后的
+1
是因为
F[0]=1是初始条件
由于 G(x) 已知,因此这是一个二次方程,解之,得
F(x)=21±1−4G(x)−−−−−−−−√
我们选择适当的符号,使得分母可逆即可。注意多项式开根号和求逆的写法,有点容易错。
#include<bits/stdc++.h>
using namespace std;
const int M=998244353,g=3;
typedef long long Int;
const int Maxn=262148;
Int rev2=(M+1)>>1;
Int a[Maxn],b[Maxn],c[Maxn],d[Maxn],G[Maxn],tp1[Maxn],tp2[Maxn],tp3[Maxn];
Int powmod(Int x,Int y,Int mod)
{
Int ret=1,t=x;
while(y){if(y&1)ret=ret*t%mod;y>>=1;t=t*t%mod;}
return ret;
}
void rev(Int *a,int n)
{
int i,j,k;
for(i=1,j=n>>1;i<n-1;i++)
{
if(i<j)swap(a[i],a[j]);
for(k=n>>1;j>=k;j-=k,k>>=1);j+=k;
}
}
void dft(Int *a,int n,int flag=1)
{
rev(a,n);
for(int m=2;m<=n;m<<=1)
{
Int wm=powmod(g,(M-1)/m,M);
if(flag<0)wm=powmod(wm,M-2,M);
for(int k=0;k<n;k+=m)
{
Int w=1;
for(int j=k;j<k+(m>>1);j++,w=w*wm%M)
{
Int u=a[j],v=a[j+(m>>1)]*w%M;
a[j]=(u+v)%M;
a[j+(m>>1)]=(u-v+M)%M;
}
}
}
}
void mul(Int *a,Int *b,int n)
{
dft(a,n);dft(b,n);
for(int i=0;i<n;i++)a[i]=a[i]*b[i]%M;
dft(a,n,-1);
int revn=powmod(n,M-2,M);
for(int i=0;i<n;i++)a[i]=a[i]*revn%M;
}
void polrev(Int *a,Int *b,Int *c,Int *d,int n)//把a变成a的%(x^n)的逆元,要求a[0]!=0
{
for(int i=0;i<(n<<1);i++)b[i]=c[i]=d[i]=0;
b[0]=powmod(a[0],M-2,M);
for(int m=2;m<=n;m<<=1)
{
for(int j=0;j<m;j++)c[j]=d[j]=b[j];
mul(d,c,m);
for(int j=0;j<m;j++)c[j]=a[j];
mul(d,c,m<<1);
for(int j=0;j<m;j++)b[j]=(b[j]*2%M-d[j]+M)%M;
}
for(int i=0;i<n;i++)a[i]=b[i];
}
void polsqrt(Int *a,Int *b,Int *c,Int *d,int n)//把a变成sqrt(a)
{
for(int i=0;i<(n<<1);i++)b[i]=c[i]=d[i]=0;
b[0]=1;//b[0]=sqrt(a[0])
for(int m=2;m<=n;m<<=1)
{
for(int j=0;j<m;j++)c[j]=b[j];
polrev(c,tp1,tp2,tp3,m);
for(int j=0;j<m;j++)d[j]=a[j];
mul(d,c,m<<1);
for(int j=0;j<m;j++)b[j]=((b[j]+d[j])%M)*rev2%M;
}
for(int i=0;i<n;i++)a[i]=b[i];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int N=1;
while(N<m+3)N<<=1;
for(int i=0;i<n;i++){int x;scanf("%d",&x);G[x]=M-4;}G[0]=1;
polsqrt(G,b,c,d,N);G[0]++;
polrev(G,b,c,d,N);
for(int i=1;i<=m;i++)printf("%I64d\n",G[i]*2%M);
}