标签:res inline std ons 多项式 == clu mit 答案
可以……这很多项式开根模板……而且也完全不知道大佬们怎么把这题的式子推出来的……
首先,这题需要多项式开根和多项式求逆。多项式求逆看这里->这里,这里讲一讲多项式开根
多项式开方:已知多项式$A$,求多项式$B$满足$A^2\equiv B\pmod{x^n}$(和多项式求逆一样这里需要取模,否则$A$可能会有无数项)
假设我们已经求出$A‘^2\equiv B\pmod{x^n}$,考虑如何计算出$A^2\equiv B\pmod{x^{2n}}$
首先肯定存在$A^2\equiv B\pmod{x^n}$
然后两式相减$$A‘^2-A^2\equiv 0\pmod{x^n}$$
$$(A‘-A)(A‘+A)\equiv 0\pmod{x^n}$$
我们假设$A‘-A\equiv 0\pmod{x^n}$,然后两边平方$$A‘^2-2A‘A+A^2\equiv 0\pmod{x^{2n}}$$
(关于平方之后模数变化的原因可以看我多项式求逆那篇文章,里面有写)
又因为$A^2\equiv B\pmod{x^{2n}}$,代入得$$A‘^2-2A‘A+B\equiv 0\pmod{x^{2n}}$$
$$A\equiv\frac{A‘^2-B}{2A‘}\pmod{x^{2n}}$$
那么这个只要递归计算就可以了
然后多项式开方就讲到这里
下面说一下本题的做法
首先,我也不知道怎么想到的构造出生成函数,$C=\sum_{i=1}^{lim}s_ix^i$,其中$s_i$表示$i$是否在集合中出现过,然后再设一个$F_k$表示权值为$k$时的答案
因为一棵二叉树可以由根节点,左右子树构成(左右子树可以是空的)
那么存在如下关系$$F_k=1+\sum_{i=1}^ks_i\sum_{j=0}^{k-i}F_jF_{i-j-k}$$
然后我也不知道怎么看出来的发现这是一个卷积的形式,即$$F=1+C*F*F$$(这里$*$是多项式乘法)
把它看做一个一元二次方程求解,得$$F=\frac{1\pm \sqrt{1-4C}}{2C}=\frac{2}{1\pm\sqrt{1-4C}}$$
然后因为$F_0=1,C_0=0$,所以符号取正,即$$F=\frac{2}{1+\sqrt{1-4C}}$$
那么把多项式开根和多项式求逆的板子带进去就好了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #define swap(x,y) (x^=y,y^=x,x^=y) 6 #define mul(x,y) (1ll*x*y%P) 7 #define add(x,y) (x+y>=P?x+y-P:x+y) 8 #define dec(x,y) (x-y<0?x-y+P:x-y) 9 using namespace std; 10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 11 char buf[1<<21],*p1=buf,*p2=buf; 12 inline int read(){ 13 #define num ch-‘0‘ 14 char ch;bool flag=0;int res; 15 while(!isdigit(ch=getc())) 16 (ch==‘-‘)&&(flag=true); 17 for(res=num;isdigit(ch=getc());res=res*10+num); 18 (flag)&&(res=-res); 19 #undef num 20 return res; 21 } 22 char sr[1<<21],z[20];int K=-1,Z; 23 inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;} 24 inline void print(int x){ 25 if(K>1<<20)Ot();if(x<0)sr[++K]=45,x=-x; 26 while(z[++Z]=x%10+48,x/=10); 27 while(sr[++K]=z[Z],--Z);sr[++K]=‘\n‘; 28 } 29 const int N=500005,P=998244353,G=3,inv2=499122177; 30 inline int ksm(int a,int b){ 31 int res=1; 32 while(b){ 33 if(b&1) res=mul(res,a); 34 a=mul(a,a),b>>=1; 35 } 36 return res; 37 } 38 int n,m,r[N],A[N],B[N],C[N],D[N],O[N],d[N],c[N]; 39 void NTT(int *A,int type,int len){ 40 int limit=1,l=0; 41 while(limit<len) limit<<=1,++l; 42 for(int i=0;i<limit;++i) 43 r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); 44 for(int i=0;i<limit;++i) 45 if(i<r[i]) swap(A[i],A[r[i]]); 46 for(int mid=1;mid<limit;mid<<=1){ 47 int R=mid<<1,Wn=ksm(G,(P-1)/R);O[0]=1; 48 for(int j=1;j<mid;++j) O[j]=mul(O[j-1],Wn); 49 for(int j=0;j<limit;j+=R){ 50 for(int k=0;k<mid;++k){ 51 int x=A[j+k],y=mul(O[k],A[j+k+mid]); 52 A[j+k]=add(x,y),A[j+k+mid]=dec(x,y); 53 } 54 } 55 } 56 if(type==-1){ 57 reverse(A+1,A+limit); 58 for(int i=0,inv=ksm(limit,P-2);i<limit;++i) 59 A[i]=mul(A[i],inv); 60 } 61 } 62 void Inv(int *a,int *b,int len){ 63 if(len==1) return (void)(b[0]=ksm(a[0],P-2)); 64 Inv(a,b,len>>1); 65 for(int i=0;i<len;++i) A[i]=a[i],B[i]=b[i]; 66 NTT(A,1,len<<1),NTT(B,1,len<<1); 67 for(int i=0,l=(len<<1);i<l;++i) A[i]=mul(mul(A[i],B[i]),B[i]); 68 NTT(A,-1,len<<1); 69 for(int i=0;i<len;++i) b[i]=dec(1ll*(b[i]<<1)%P,A[i]); 70 for(int i=0,l=(len<<1);i<l;++i) A[i]=B[i]=0; 71 } 72 void Sqrt(int *a,int *b,int len){ 73 if(len==1) return (void)(b[0]=a[0]); 74 Sqrt(a,b,len>>1); 75 for(int i=0;i<len;++i) C[i]=a[i]; 76 Inv(b,D,len); 77 NTT(C,1,len<<1),NTT(D,1,len<<1); 78 for(int i=0,l=len<<1;i<l;++i) D[i]=mul(D[i],C[i]); 79 NTT(D,-1,len<<1); 80 for(int i=0;i<len;++i) b[i]=mul(add(b[i],D[i]),inv2); 81 for(int i=0,l=(len<<1);i<l;++i) C[i]=D[i]=0; 82 } 83 int main(){ 84 // freopen("testdata.in","r",stdin); 85 n=read(),m=read(); 86 for(int i=1,x;i<=n;++i) x=read(),++d[x]; 87 int len;for(len=1;len<=m;len<<=1); 88 for(int i=1;i<len;++i) d[i]=(-4*d[i]+P)%P; 89 ++d[0]; 90 Sqrt(d,c,len); 91 for(int i=0;i<len;++i) d[i]=0; 92 c[0]=add(c[0],1); 93 Inv(c,d,len); 94 for(int i=0;i<=m;++i) d[i]=add(d[i],d[i]); 95 for(int i=1;i<=m;++i) print(d[i]); 96 Ot(); 97 return 0; 98 }
CF438E The Child and Binary Tree(生成函数+多项式开根+多项式求逆)
标签:res inline std ons 多项式 == clu mit 答案
原文地址:https://www.cnblogs.com/bztMinamoto/p/9747126.html