设f(n)为权值为n的神犇二叉树个数。考虑如何递推求这个东西。
套路地枚举根节点的左右子树。则f(n)=Σf(i)f(n-i-cj),cj即根的权值。卷积的形式,cj也可以通过卷上一个多项式枚举。可以考虑生成函数。
设F(x)为f(n)的生成函数,G(x)为c(n)的生成函数,G(x)中含有xa项表示存在ci=a。于是可得F(x)=F2(x)G(x)+1。+1是因为枚举根的权值时没有考虑空树即根没有权值的情况。
可以解出F(x)={1±√[1-4G(x)]}/2G(x)=2/{1±√[1-4G(x)]}。由F(0)=1,G(0)=0,可得F(x)=2/{1+√[1-4G(x)]}。
于是求出来这个就好了。需要一个多项式开根和多项式求逆,原理类似,有B(x)=(A(x)+B'(x)2)/2B'(x)。多项式开根的常数项原本是需要求二次剩余的,不过显然在这里其常数项为1。
各种数组混用没清零调了好长时间。并且开始写丑到一个境界以至于要开八倍数组。虽然改成了开四倍还是在bzoj上t掉了。辣鸡板子活该t。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 550000 #define P 998244353 #define inv3 332748118 int n,m,a[N],b[N],c[N],d[N],e[N],r[N]; int ksm(int a,int k) { if (k==0) return 1; int tmp=ksm(a,k>>1); if (k&1) return 1ll*tmp*tmp%P*a%P; else return 1ll*tmp*tmp%P; } void DFT(int n,int *a,int p) { for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|(i&1)*(n>>1); for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]); for (int i=2;i<=n;i<<=1) { int wn=ksm(p,(P-1)/i); for (int j=0;j<n;j+=i) { int w=1; for (int k=j;k<j+(i>>1);k++,w=1ll*w*wn%P) { int x=a[k],y=1ll*w*a[k+(i>>1)]%P; a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P; } } } } void mul(int n,int *a,int *b) { DFT(n,a,3),DFT(n,b,3); for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%P; DFT(n,a,inv3);DFT(n,b,inv3); int inv=ksm(n,P-2); for (int i=0;i<n;i++) a[i]=1ll*a[i]*inv%P,b[i]=1ll*b[i]*inv%P; } void inv(int n) { int t=1; for (int i=0;i<=n;i++) e[i]=a[i],a[i]=d[i]=0; a[0]=ksm(e[0],P-2); while (t<=n) { t<<=1; for (int i=0;i<t;i++) d[i]=e[i]; t<<=1; mul(t,d,a); for (int i=0;i<(t>>1);i++) d[i]=(P-d[i])%P; for (int i=(t>>1);i<t;i++) d[i]=0; d[0]=(d[0]+2)%P; mul(t,a,d); for (int i=(t>>1);i<t;i++) a[i]=0; t>>=1; } for (int i=n+1;i<t;i++) a[i]=0; } void Sqrt(int n) { int t=1; memcpy(b,a,sizeof(b)); memset(a,0,sizeof(a));a[0]=1; while (t<=n) { t<<=1; for (int i=0;i<t;i++) c[i]=a[i]; t<<=1; mul(t,c,a); for (int i=0;i<(t>>1);i++) c[i]=(c[i]+b[i])%P; for (int i=(t>>1);i<t;i++) c[i]=0; for (int i=0;i<(t>>1);i++) a[i]=(a[i]<<1)%P; inv(t-1); for (int i=(t>>1);i<t;i++) a[i]=0; mul(t,a,c); for (int i=(t>>1);i<t;i++) a[i]=0; t>>=1; } for (int i=n+1;i<t;i++) a[i]=0; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3625.in","r",stdin); freopen("bzoj3625.out","w",stdout); const char LL[]="%I64d"; #else const char LL[]="%lld"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) b[a[i]]=P-4; b[0]=1; memcpy(a,b,sizeof(a)); Sqrt(m); a[0]++;if (a[0]>=P) a[0]-=P; inv(m); for (int i=1;i<=m;i++) a[i]=(a[i]<<1)%P; for (int i=1;i<=m;i++) printf("%d\n",a[i]); return 0; }