【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题...
我们不妨去推下此题的生成函数,设生成函数为F(x),则[xs]F(x)即为答案。
根据题意,我们得到 F(x)=x+∑i∈DFi(x),其中前面单独出现的x可以理解为空树的情况。
如果i的范围很小,那么我们就可以用求根公式去解多项式方程23333。
然而考虑到i最大为105,根据阿贝尔定理,无根式解,所以不能用此方法。
我们对原先的式子做一个移项,得F(x)−∑i∈DFi(x)=x。
我们构造函数G(x)=x−∑i∈Dxi。
不难发现G(F(x))=F(x)−∑i∈DFi(x)=x。也就是说F(x)和G(x)互为反函数。
然后我们现在已知G(x),要求F(x)使得G(F(x))=x。也就是求G(x)的复合逆。
根据拉格朗日反演,若G(F(x))=x,则有[xs]F(x)=1s[x−1]1Gs(x)。
然后,我们对式子乘上xs,得到[xs]F(x)=1s[xs−1](1G(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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!