bzoj 3684: 大朋友和多叉树 生成函数
2016-04-17 18:47
387 查看
关于生成函数,可以见金策爷的课件。
设F为多叉树的生成函数,第n项表示根权值为n时的方案数;C为儿子的生成函数,那么有:
F(x)=Σi∈(S)F(x)^i+x,也就是F(x)=C(F(x))+x,移项得到F(x)-C(F(x))=x,那么令G(x)=x-C(x),就有:G(F(x))=x,因此F(x)是G(x)的复合逆。然后运用拉格朗日反演:
[x^n]F(x)=1/n(x^(n-1))(x/G(x))^n。。证明课件里面也没有讲QAQ。
就变成求逆和求多项式的n次了。。。前面的用多项式求逆,后面的可以拆成epx(ln(x/G(x))*n),具体课件里有。
然后就变成抄代码时间辣T_T。
AC代码如下:
by lych
2016.4.17
设F为多叉树的生成函数,第n项表示根权值为n时的方案数;C为儿子的生成函数,那么有:
F(x)=Σi∈(S)F(x)^i+x,也就是F(x)=C(F(x))+x,移项得到F(x)-C(F(x))=x,那么令G(x)=x-C(x),就有:G(F(x))=x,因此F(x)是G(x)的复合逆。然后运用拉格朗日反演:
[x^n]F(x)=1/n(x^(n-1))(x/G(x))^n。。证明课件里面也没有讲QAQ。
就变成求逆和求多项式的n次了。。。前面的用多项式求逆,后面的可以拆成epx(ln(x/G(x))*n),具体课件里有。
然后就变成抄代码时间辣T_T。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #define ll long long #define mod 950009857 #define N 270005 using namespace std; int f ,g ,c ,h ,q ,inv ,pos ,na ; int ksm(int x,int y){ int t=1; for (; y; y>>=1,x=(ll)x*x%mod) if (y&1) t=(ll)t*x%mod; return t; } void getpos(int n){ int cnt=0,i,j,k; for (k=1; k<n; k<<=1) cnt++; for (i=0; i<n; i++){ k=i; pos[i]=0; for (j=1; j<=cnt; j++,k>>=1) pos[i]=pos[i]<<1|(k&1); } } void fnt(int *a,int n,int p){ int i,j,k,w,wn,u,v; //for (i=0; i<n; i++) cout<<a[i]<<' '; puts(""); for (i=0; i<n; i++) na[pos[i]]=a[i]; memcpy(a,na,sizeof(a[0])*n); for (k=1; k<n; k<<=1){ wn=ksm(7,(ll)((mod-1)>>1)/k*p%(mod-1)); for (i=0; i<n; i+=(k<<1)){ w=1; for (j=i; j<i+k; j++,w=(ll)w*wn%mod){ u=a[j]; v=(ll)a[j+k]*w%mod; a[j]=(u+v)%mod; a[j+k]=(u+mod-v)%mod; } } } //for (i=0; i<n; i++) cout<<a[i]<<' ';puts("");puts(""); if (p+2==mod) for (i=0; i<n; i++) a[i]=(ll)a[i]*inv %mod; } void solve_inv(int *a,int *b,int n){ if (n==1){ b[0]=ksm(a[0],mod-2); return; } solve_inv(a,b,n>>1); int i; memcpy(c,a,sizeof(a[0])*n); memset(c+n,0,sizeof(c[0])*n); getpos(n<<1); fnt(b,n<<1,1); fnt(c,n<<1,1); for (i=0; i<(n<<1); i++) b[i]=(ll)b[i]*(2-(ll)b[i]*c[i]%mod+mod)%mod; fnt(b,n<<1,mod-2); memset(b+n,0,sizeof(b[0])*n); } void solve_ln(int *a,int *b,int n){ memset(q,0,sizeof(q[0])*(n<<1)); solve_inv(a,q,n); memset(c,0,sizeof(c[0])*(n<<1)); int i; for (i=0; i+1<n; i++) c[i]=(ll)a[i+1]*(i+1)%mod; getpos(n<<1); fnt(q,n<<1,1); fnt(c,n<<1,1); for (i=0; i<(n<<1); i++) b[i]=(ll)q[i]*c[i]%mod; fnt(b,n<<1,mod-2); for (i=n-1; i; i--) b[i]=(ll)b[i-1]*inv[i]%mod; b[0]=0; memset(b+n,0,sizeof(b[0])*n); } void solve_exp(int *a,int *b,int n){ if (n==1){ b[0]=1; return; } solve_exp(a,b,n>>1); int i; memset(h,0,sizeof(h[0])*(n<<1)); solve_ln(b,h,n); for (i=0; i<n; i++) h[i]=(a[i]-h[i]+mod)%mod; h[0]=(h[0]+1)%mod; getpos(n<<1); fnt(b,n<<1,1); fnt(h,n<<1,1); for (i=0; i<(n<<1); i++) b[i]=(ll)b[i]*h[i]%mod; fnt(b,n<<1,mod-2); memset(b+n,0,sizeof(b[0])*n); } int main(){ int i,x,n,len,m; scanf("%d%d",&len,&m); for (i=1; i<=m; i++){ scanf("%d",&x); f[x-1]=mod-1; } f[0]=inv[1]=n=1; while (n<=len) n<<=1; for (i=2; i<=(n<<1); i++) inv[i]=mod-(ll)inv[mod%i]*(mod/i)%mod; solve_inv(f,g,n); memset(f,0,sizeof(f)); solve_ln(g,f,n); for (i=0; i<n; i++) f[i]=(ll)f[i]*len%mod; memset(g,0,sizeof(g)); solve_exp(f,g,n); printf("%d\n",(ll)g[len-1]*ksm(len,mod-2)%mod); return 0; }
by lych
2016.4.17
相关文章推荐
- 约瑟夫环问题及其尽可能的优化
- 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●
- 装饰者模式
- [BZOJ1031][JSOI2007]字符加密Cipher(后缀数组)
- iframe和response.sendRedirect使用的问题
- hive jdbc程序开发
- Servlet细节问题
- mysql之explain详解(分析索引的最佳使用)
- 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。
- 【DS】atoi()实现
- Java方法参数传递方式总结
- 理解进程调度时机跟踪分析进程调度与进程切换的过程
- Linux:-bash: ***: command not found
- Differences between Octave and MATLAB
- Android TextView 实现文字大小不同和文字颜色不同
- 理解进程调度时机跟踪分析进程调度与进程切换的过程
- Servlet的调用过程_生命周期_继承结构
- 博弈+
- Maven入门系列(二)--设置中央仓库的方法
- Hadoop家族环境搭建各种版本选择