[Codeforces Round #250]小朋友和二叉树
题目描述:
题解:
生成函数ntt。
显然这种二叉树应该暴力薅掉树根然后分裂成两棵子树。
所以$f(x)= \sum_{i \in c} \sum _{j=0}^{x-c} f(i)*f(x-i-j)$
这是个不好看的卷积。
所以我们再引入$c$的生成函数$G$,那么有$$F(x)=1+G(x)*F(x)*F(x)$$
注意常数项,因为正常$f(0)=1$但是$G(0)=0$,所以要人为配常数。
然后$F= \frac{1 \pm \sqrt{1-4G}} {2G} = \frac{2}{1 \pm \sqrt{1-4G}}$
还是因为系数,正负号只能取正。
bz严重卡常:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 540050; const int MOD = 998244353; const int inv_2 = ((MOD+1)>>1); template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } inline void Mod(unsigned int&x){if(x>=MOD)x-=MOD;} inline unsigned int fastpow(unsigned int x,int y) { int ret = 1; while(y) { if(y&1)ret=1ll*ret*x%MOD; x=1ll*x*x%MOD;y>>=1; } return ret; } int inv(const unsigned int x){return fastpow(x,MOD-2);} int to[N],lim,L,LL[N],n,m; inline void init(const int len) { lim=LL[2]=1; while(lim<=len)lim<<=1,LL[lim<<1]=LL[lim]+1; } unsigned int W[N],INV; inline void get_lim(const int len) { lim = len,L = LL[len]; for(register int i=1;i<lim;++i)to[i]=((to[i>>1]>>1)|((i&1)<<(L-1))); INV = inv(len); for(register int i=1;i<lim;i<<=1)W[i]=fastpow(3,(MOD-1)/(i<<1)); } inline void ntt(unsigned int*a,const int len,const int k) { for(register int i=0;i<len;++i) if(i<to[i])swap(a[i],a[to[i]]); for(register int i=1;i<len;i<<=1) { unsigned int w0 = W[i]; for(register int j=0;j<len;j+=(i<<1)) { unsigned int w = 1; for(register int o=0;o<i;++o,w=1ll*w*w0%MOD) { unsigned int w1 = a[j+o],w2 = 1ll*a[j+o+i]*w%MOD; Mod(a[j+o]=w1+w2); Mod(a[j+o+i]=w1+MOD-w2); } } } if(k==-1) { for(register int i=1;i<len>>1;++i)swap(a[i],a[len-i]); for(register int i=0;i<len;++i)a[i]=1ll*a[i]*INV%MOD; } } unsigned int a[N],b[N],c[N]; void mul(unsigned int*F,unsigned int*G,unsigned int*H,const int len) { get_lim(len<<1); for(register int i=0;i<lim;++i)a[i]=b[i]=0; for(register int i=0;i<len;++i)a[i]=F[i],b[i]=G[i]; ntt(a,lim,1),ntt(b,lim,1); for(register int i=0;i<lim;++i)c[i]=1ll*a[i]*b[i]%MOD; ntt(c,lim,-1); for(register int i=0;i<lim;++i)H[i]=c[i]; } unsigned int T[N]; void get_inv(unsigned int*F,unsigned int*G,const int len) { if(len==1){G[0]=inv(F[0]),G[1]=0;return ;} get_inv(F,G,len>>1); get_lim(len<<1);for(register int i=0;i<lim;++i)a[i]=b[i]=0; for(register int i=0;i<len;++i)a[i]=F[i];for(register int i=0;i<(len>>1);++i)b[i]=G[i]; ntt(a,lim,1),ntt(b,lim,1);for(register int i=0;i<lim;++i)c[i]=1ll*a[i]*b[i]%MOD*b[i]%MOD;ntt(c,lim,-1); for(register int i=0;i<len;++i)G[i]=(2ll*G[i]+MOD-c[i])%MOD,G[i+len]=0; } unsigned int H[N]; void get_sqrt(unsigned int*F,unsigned int*G,const int len) { if(len==1){G[0]=1;return ;} get_sqrt(F,G,len>>1);get_inv(G,H,len); mul(G,G,T,len);for(register int i=0;i<len;++i)T[i]=1ll*(T[i]+F[i])*inv_2%MOD; mul(H,T,G,len);for(register int i=len;i<(len<<1);++i)G[i]=0; } unsigned int F[N],G[N],S[N]; int main() { // freopen("tt.in","r",stdin); read(n),read(m); init(m);int c,mx = lim; for(register int i=1;i<=n;++i) read(c),G[c]=MOD-4; G[0]++; get_sqrt(G,S,mx); S[0]++; for(register int i=0;i<mx;++i)S[i]=1ll*S[i]*inv_2%MOD; get_inv(S,F,mx); for(register int i=1;i<=m;++i) printf("%u\n",F[i]); return 0; }