【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题...
我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案。
根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$,其中前面单独出现的$x$可以理解为空树的情况。
如果$i$的范围很小,那么我们就可以用求根公式去解多项式方程23333。
然而考虑到$i$最大为$10^5$,根据阿贝尔定理,无根式解,所以不能用此方法。
我们对原先的式子做一个移项,得$F(x)-\sum_{i∈D} F^i(x)=x$。
我们构造函数$G(x)=x-\sum_{i∈D}x^i$。
不难发现$G(F(x))=F(x)-\sum_{i∈D}F^i(x)=x$。也就是说$F(x)$和$G(x)$互为反函数。
然后我们现在已知$G(x)$,要求$F(x)$使得$G(F(x))=x$。也就是求$G(x)$的复合逆。
根据拉格朗日反演,若$G(F(x))=x$,则有$[x^s]F(x)=\dfrac{1}{s}[x^{-1}]\dfrac{1}{G^s(x)}$。
然后,我们对式子乘上$x^s$,得到$[x^s]F(x)=\dfrac{1}{s}[x^{s-1}](\dfrac{1}{G(x)})^s$。
然后后面就是多项式快速幂了。
1 #include<bits/stdc++.h> 2 #define G 7 3 #define L long long 4 #define MOD 950009857 5 #define inv(x) pow_mod(x,MOD-2) 6 #define M 1<<18 7 using namespace std; 8 9 L pow_mod(L x,L k){ 10 L ans=1; 11 while(k){ 12 if(k&1) ans=ans*x%MOD; 13 k=k>>1; x=x*x%MOD; 14 } 15 return ans; 16 } 17 18 void change(L a[],int n){ 19 for(int i=0,j=0;i<n-1;i++){ 20 if(i<j) swap(a[i],a[j]); 21 int k=n>>1; 22 while(j>=k) j-=k,k>>=1; 23 j+=k; 24 } 25 } 26 void NTT(L a[],int n,int on){ 27 change(a,n); 28 for(int h=2;h<=n;h<<=1){ 29 L wn=pow_mod(G,(MOD-1)/h); 30 for(int j=0;j<n;j+=h){ 31 L w=1; 32 for(int k=j;k<j+(h>>1);k++){ 33 L u=a[k],t=a[k+(h>>1)]*w%MOD; 34 a[k]=(u+t)%MOD; 35 a[k+(h>>1)]=(u-t+MOD)%MOD; 36 w=w*wn%MOD; 37 } 38 } 39 } 40 if(on==-1){ 41 L inv=inv(n); 42 for(int i=0;i<n;i++) a[i]=a[i]*inv%MOD; 43 reverse(a+1,a+n); 44 } 45 } 46 47 void getinv(L a[],L b[],int n){ 48 if(n==1) return void(b[0]=inv(a[0])); 49 static L A[M],B[M]; 50 memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); 51 getinv(a,B,n>>1); 52 for(int i=0;i<n;i++) A[i]=a[i]; 53 NTT(A,n<<1,1); NTT(B,n<<1,1); 54 for(int i=0;i<(n<<1);i++) b[i]=(2*B[i]-A[i]*B[i]%MOD*B[i]%MOD+MOD)%MOD; 55 NTT(b,n<<1,-1); 56 for(int i=0;i<n;i++) b[n+i]=0; 57 } 58 59 void qiudao(L a[],L b[],int n){ 60 memset(b,0,sizeof(b)); 61 for(int i=1;i<n;i++) b[i-1]=i*a[i]%MOD; 62 } 63 void jifen(L a[],L b[],int n){ 64 memset(b,0,sizeof(b)); 65 for(int i=0;i<n;i++) b[i+1]=a[i]*pow_mod(i+1,MOD-2)%MOD; 66 } 67 68 void getln(L a[],L b[],int n){ 69 static L c[M],d[M]; 70 memset(c,0,M<<3); memset(d,0,M<<3); 71 qiudao(a,c,n); getinv(a,d,n); 72 NTT(c,n<<1,1); NTT(d,n<<1,1); 73 for(int i=0;i<(n<<1);i++) c[i]=c[i]*d[i]%MOD; 74 NTT(c,n<<1,-1); 75 jifen(c,b,n); 76 } 77 78 void getexp(L a[],L b[],int n){ 79 if(n==1){b[0]=1; return;} 80 static L lnb[M]; memset(lnb,0,M<<3); 81 getexp(a,b,n>>1); getln(b,lnb,n); 82 for(int i=0;i<n;i++) lnb[i]=(a[i]-lnb[i]+MOD)%MOD; 83 lnb[n]=0; 84 lnb[0]=(lnb[0]+1)%MOD; 85 NTT(lnb,n<<1,1); NTT(b,n<<1,1); 86 for(int i=0;i<(n<<1);i++) b[i]=b[i]*lnb[i]%MOD; 87 NTT(b,n<<1,-1); 88 for(int i=0;i<n;i++) b[i+n]=0; 89 } 90 91 L g[M]={0},f[M]={0}; 92 93 void pow_mod(L a[],L b[],int n,int k){ 94 memset(b,0,M<<3); 95 getln(a,b,n); 96 for(int i=0;i<n;i++) a[i]=b[i]*k%MOD; 97 memset(b,0,M<<3); 98 getexp(a,b,n); 99 } 100 101 int main(){ 102 int n,m; 103 scanf("%d%d",&n,&m); 104 for(int i=1;i<=m;i++){ 105 int x; scanf("%d",&x); 106 g[x-1]=-1; 107 } 108 g[0]=1; 109 int nn=1;while(nn<n) nn<<=1; 110 getinv(g,f,nn); 111 memset(g,0,sizeof(g)); 112 pow_mod(f,g,nn,n); 113 L ans=inv(n)*g[n-1]%MOD; 114 cout<<ans<<endl; 115 }