先来列一个暴力\(dp\),\(dp_i\)表示形成\(i\)点权的二叉树的方案数
我们可以直接列出方程
\[ dp_i=\sum_{k=1}^n\sum_{j=0}^{i-c_k}dp_jdp_{i-c_k-j} \]
边界条件\(dp_0=1\)
\[ F(x)=\sum_{i=0}([i=0]+\sum_{k=1}^n\sum_{j=0}^{i-c_k}dp_jdp_{i-c_k-j})x^i \]
\[ F(x)=1+\sum_{k=1}^nx^{c_k}\sum_{j=0}^{i-c_k}dp_jx^j\times dp_{i-c_k-j}x^{i-c_k-j} \]
发现里面就是\(F^2(x)\),于是
\[ F(x)=1+\sum_{k=1}^nx^{c_k}F^2(x) \]
发现有一个乘以\(x^{c_k}\)之后再求和,设那个多项式为\(G(x)\),不就是卷上那边的那个多项式吗
\[ F(x)=1+G(x)F^2(x) \]
于是我们可以解方程了
发现
\[ F(x)=\frac{1\pm \sqrt{1-4G(x)}}{2G(x)} \]
发现取正不收敛,于是
\[ F(x)=\frac{1- \sqrt{1-4G(x)}}{2G(x)}=\frac{4G(x)}{2G(x)(1+\sqrt{1-4G(x)})}=\frac{2}{1+\sqrt{1-4G(x)}} \]
于是我们多项式求逆+多项式开根就能搞了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define re register #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) const int maxn=262144+1005; inline int read() { char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } const LL mod=998244353; const LL G[2]={3,332748118}; LL A[maxn],B[maxn],C[maxn],K[maxn],D[maxn],H[maxn],T[maxn],F[maxn]; LL a[maxn],b[maxn]; int n,m,rev[maxn],len; inline LL ksm(LL a,int b) {LL S=1;while(b){if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;} inline void NTT(LL *f,int o) { for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]); for(re int i=2;i<=len;i<<=1) { int ln=i>>1;LL og1=ksm(G[o],(mod-1)/i); for(re int l=0;l<len;l+=i) { LL t,og=1; for(re int x=l;x<l+ln;x++) { t=(og*f[ln+x])%mod; f[ln+x]=(f[x]-t+mod)%mod; f[x]=(f[x]+t)%mod; og=(og*og1)%mod; } } } if(!o) return; LL inv=ksm(len,mod-2); for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod; } inline void mul(LL *A,LL *B,int n) { len=1;while(len<n+n) len<<=1; for(re int i=0;i<len;i++) rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0); NTT(A,0),NTT(B,0); for(re int i=0;i<len;i++) A[i]=(A[i]*B[i])%mod; NTT(A,1);for(re int i=n;i<len;i++) A[i]=0; } inline void Inv(int n,LL *A,LL *B) { if(n==1) {B[0]=ksm(A[0],mod-2);return;} Inv((n+1)>>1,A,B); memset(C,sizeof(C));memset(K,sizeof(K)),memset(D,sizeof(D)); for(re int i=0;i<n;i++) C[i]=A[i],D[i]=K[i]=B[i]; mul(K,C,n);mul(K,D,n); for(re int i=0;i<n;i++) B[i]=(2ll*B[i]-K[i]+mod)%mod; } inline void Sqrt(int n,LL *B) { if(n==1) {B[0]=1;return;} Sqrt((n+1)>>1,B); memset(H,sizeof(H));memset(F,sizeof(F));memset(T,sizeof(T)); for(re int i=0;i<n;i++) F[i]=B[i],T[i]=2ll*B[i]; Inv(n,T,H);mul(B,F,n); for(re int i=0;i<n;i++) B[i]=(B[i]+A[i])%mod; mul(B,H,n); } int main() { n=read(),m=read(); for(re int i=1;i<=n;i++) a[read()]+=4; for(re int i=0;i<=m;i++) a[i]=mod-a[i],a[i]%=mod; a[0]++;Sqrt(m+1,a,A);A[0]++;Inv(m+1,b); for(re int i=1;i<=m;i++) printf("%lld\n",2ll*b[i]%mod); return 0; }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。