CF438E The Child and Binary Tree 題解
阿新 • • 發佈:2021-08-24
CF438E The Child and Binary Tree
本文版權歸 Azazel 與部落格園共有,歡迎轉載,但需保留此宣告,並給出原文地址,謝謝合作。
原文地址:https://www.cnblogs.com/Azazel/p/15182481.html
題意
\(~~~~\) 給出 \(n\) 個權值 \(c_i\),求有多少棵二叉樹,其所有的點權均在這些權值之中且點權和為 \(S\in[1,m]\)。答案對 \(998244353\) 取模。
\(~~~~\) \(1\leq n,m,c_i\leq 10^5\)
題解
\(~~~~\) 首先考慮 \(\texttt{DP}\),設 \(f_{i}\)
\(~~~~\) 先有初始值 \(f_0=1\) ,則可以推出下面這個式子:
\[\large f_{i}=\sum_{j=1}^ig_i\sum_{k=0}^{i-j}f_k\times f_{i-k-j} \]\(~~~~\) 然後不難發現把 \(f\) 和 \(g\) 看作多項式後就是個卷積形式:
\[\large f=g\ *\ f^2+1 \]\(~~~~\) 由於 \(g\) 已知,我們試圖通過此來推一波 \(f\) :
\[\large g * f^2-f+1=0\\ \large f=\dfrac{1 \pm \sqrt{1-4g}}{2g} \]\(~~~~\)
\(~~~~\) 理論上可做了,但是我們發現 \([x^0]g(x)=0\) ,不能求逆,所以我們進行一波分子有理化(或者叫分母無理化?):
\[\dfrac{2}{1+\sqrt{1-4g}} \]\(~~~~\) 然後多項式開根+求逆套上來即可卷出 \(f\) 。
程式碼
檢視程式碼
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; const ll MOD=998244353; ll To[5000005],N; ll qpow(ll a,ll b) { ll ret=1; while(b) { if(b&1) ret=ret*a%MOD; b>>=1;a=a*a%MOD; } return ret; } const ll g=3,gi=qpow(g,MOD-2); const ll Inv2=qpow(2,MOD-2); inline ll Add(ll a,ll b){return ((a+b)%MOD+MOD)%MOD;} inline ll Mul(ll a,ll b){return a*b%MOD;} void NTT(ll *S,ll op) { for(int i=0;i<N;i++) if(i<To[i]) swap(S[i],S[To[i]]); for(int i=1;i<N;i<<=1) { ll W=qpow(op==1?g:gi,(MOD-1)/(i<<1)); for(int j=0;j<N;j+=i<<1) { ll w=1; for(int k=0;k<i;k++,w=w*W%MOD) { ll x=S[j+k],y=Mul(S[i+j+k],w); S[j+k]=Add(x,y);S[i+j+k]=Add(x,-y); } } } if(op==-1) { ll Inv=qpow(N,MOD-2); for(int i=0;i<N;i++) S[i]=Mul(S[i],Inv); } } ll C[5000005]; void GetInv(int deg,ll *A,ll *B) { if(deg==1){B[0]=qpow(A[0],MOD-2);return;} GetInv((deg+1)>>1,A,B); for(N=1;N<=(deg<<1);N<<=1); for(int i=0;i<N;i++) To[i]=(To[i>>1]>>1)|((i&1)*(N>>1)),C[i]=A[i]; for(int i=deg;i<N;i++) C[i]=0; NTT(C,1);NTT(B,1); for(int i=0;i<N;i++) B[i]=Mul(Add(2ll,-Mul(C[i],B[i])),B[i]); NTT(B,-1); for(int i=deg;i<N;i++) B[i]=0; } ll inv[5000005],D[5000005]; void GetSqrt(int deg,ll *A,ll *B) { if(deg==1){B[0]=1;return;} GetSqrt((deg+1)>>1,A,B); for(N=1;N<=(deg<<1);N<<=1); for(int i=0;i<N;i++) To[i]=(To[i>>1]>>1)|((i&1)*(N>>1)),D[i]=inv[i]=0; for(int i=0;i<deg;i++) D[i]=A[i]; GetInv(deg,B,inv); NTT(inv,1);NTT(D,1);NTT(B,1); for(int i=0;i<N;i++) B[i]=Mul(Add(B[i],Mul(D[i],inv[i])),Inv2); NTT(B,-1); for(int i=deg;i<N;i++) B[i]=0; } template<typename T>void read(T &x) { T f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();} x*=f; } template<typename T>void print(T x) { if(x<0) putchar('-'),x=-x; if(x>9) print(x/10); putchar(x%10+'0'); } ll F[1000005],G[1000005],H[1000005]; int main() { int n,m; scanf("%d %d",&n,&m); for(int i=1,x;i<=n;i++) { scanf("%d",&x); G[x]=1; } G[0]=1; for(int i=1;i<=m;i++) G[i]=(MOD-4*G[i]%MOD)%MOD; GetSqrt(m+1,G,F);F[0]++; GetInv(m+1,F,H); for(int i=0;i<=m;i++) H[i]=H[i]*2%MOD; for(int i=1;i<=m;i++) printf("%lld\n",H[i]); return 0; }