这题一看就觉得是生成函数的题...

我们不妨去推下此题的生成函数,设生成函数为$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=;
  11. while(k){
  12. if(k&) ans=ans*x%MOD;
  13. k=k>>; x=x*x%MOD;
  14. }
  15. return ans;
  16. }
  17.  
  18. void change(L a[],int n){
  19. for(int i=,j=;i<n-;i++){
  20. if(i<j) swap(a[i],a[j]);
  21. int k=n>>;
  22. while(j>=k) j-=k,k>>=;
  23. j+=k;
  24. }
  25. }
  26. void NTT(L a[],int n,int on){
  27. change(a,n);
  28. for(int h=;h<=n;h<<=){
  29. L wn=pow_mod(G,(MOD-)/h);
  30. for(int j=;j<n;j+=h){
  31. L w=;
  32. for(int k=j;k<j+(h>>);k++){
  33. L u=a[k],t=a[k+(h>>)]*w%MOD;
  34. a[k]=(u+t)%MOD;
  35. a[k+(h>>)]=(u-t+MOD)%MOD;
  36. w=w*wn%MOD;
  37. }
  38. }
  39. }
  40. if(on==-){
  41. L inv=inv(n);
  42. for(int i=;i<n;i++) a[i]=a[i]*inv%MOD;
  43. reverse(a+,a+n);
  44. }
  45. }
  46.  
  47. void getinv(L a[],L b[],int n){
  48. if(n==) return void(b[]=inv(a[]));
  49. static L A[M],B[M];
  50. memset(A,,sizeof(A)); memset(B,,sizeof(B));
  51. getinv(a,B,n>>);
  52. for(int i=;i<n;i++) A[i]=a[i];
  53. NTT(A,n<<,); NTT(B,n<<,);
  54. for(int i=;i<(n<<);i++) b[i]=(*B[i]-A[i]*B[i]%MOD*B[i]%MOD+MOD)%MOD;
  55. NTT(b,n<<,-);
  56. for(int i=;i<n;i++) b[n+i]=;
  57. }
  58.  
  59. void qiudao(L a[],L b[],int n){
  60. memset(b,,sizeof(b));
  61. for(int i=;i<n;i++) b[i-]=i*a[i]%MOD;
  62. }
  63. void jifen(L a[],L b[],int n){
  64. memset(b,,sizeof(b));
  65. for(int i=;i<n;i++) b[i+]=a[i]*pow_mod(i+,MOD-)%MOD;
  66. }
  67.  
  68. void getln(L a[],L b[],int n){
  69. static L c[M],d[M];
  70. memset(c,,M<<); memset(d,,M<<);
  71. qiudao(a,c,n); getinv(a,d,n);
  72. NTT(c,n<<,); NTT(d,n<<,);
  73. for(int i=;i<(n<<);i++) c[i]=c[i]*d[i]%MOD;
  74. NTT(c,n<<,-);
  75. jifen(c,b,n);
  76. }
  77.  
  78. void getexp(L a[],L b[],int n){
  79. if(n==){b[]=; return;}
  80. static L lnb[M]; memset(lnb,,M<<);
  81. getexp(a,b,n>>); getln(b,lnb,n);
  82. for(int i=;i<n;i++) lnb[i]=(a[i]-lnb[i]+MOD)%MOD;
  83. lnb[n]=;
  84. lnb[]=(lnb[]+)%MOD;
  85. NTT(lnb,n<<,); NTT(b,n<<,);
  86. for(int i=;i<(n<<);i++) b[i]=b[i]*lnb[i]%MOD;
  87. NTT(b,n<<,-);
  88. for(int i=;i<n;i++) b[i+n]=;
  89. }
  90.  
  91. L g[M]={},f[M]={};
  92.  
  93. void pow_mod(L a[],L b[],int n,int k){
  94. memset(b,,M<<);
  95. getln(a,b,n);
  96. for(int i=;i<n;i++) a[i]=b[i]*k%MOD;
  97. memset(b,,M<<);
  98. getexp(a,b,n);
  99. }
  100.  
  101. int main(){
  102. int n,m;
  103. scanf("%d%d",&n,&m);
  104. for(int i=;i<=m;i++){
  105. int x; scanf("%d",&x);
  106. g[x-]=-;
  107. }
  108. g[]=;
  109. int nn=;while(nn<n) nn<<=;
  110. getinv(g,f,nn);
  111. memset(g,,sizeof(g));
  112. pow_mod(f,g,nn,n);
  113. L ans=inv(n)*g[n-]%MOD;
  114. cout<<ans<<endl;
  115. }

【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演的更多相关文章

  1. BZOJ3684 大朋友和多叉树(多项式相关计算)

    设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数.不难得出$f(x)=\sum_{k\in D}f(x)^k+x$我们要求这个多项式的第$n$项,由拉格朗日反演可得$[x ...

  2. [BZOJ3684]大朋友和多叉树

    设答案为$f_s$,它的生成函数为$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i\end{align*}$,则我们有$\begin{align* ...

  3. 【xsy2479】counting 生成函数+多项式快速幂

    题目大意:在字符集大小为$m$的情况下,有多少种构造长度为$n$的字符串$s$的方案,使得$C(s)=k$.其中$C(s)$表示字符串$s$中出现次数最多的字符的出现次数. 对$998244353$取 ...

  4. bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)

    题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...

  5. BZOJ3992 [SDOI2015]序列统计 【生成函数 + 多项式快速幂】

    题目 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问题 ...

  6. BZOJ 3684: 大朋友和多叉树 [拉格朗日反演 多项式k次幂 生成函数]

    3684: 大朋友和多叉树 题意: 求有n个叶子结点,非叶节点的孩子数量\(\in S, a \notin S\)的有根树个数,无标号,孩子有序. 鏼鏼鏼! 树的OGF:\(T(x) = \sum_{ ...

  7. 【BZOJ3684】大朋友和多叉树(拉格朗日反演)

    题目链接 题意 求满足如下条件的多叉树个数: 1.每一个点的儿子个数在给定的集合 \(S\) 内 2.总的叶子节点树为 \(s\) 儿子之间有顺序关系,但节点是没有标号的. Sol 拉格朗日反演板子题 ...

  8. BZOJ 3684 大朋友和多叉树

    BZOJ 3684 大朋友和多叉树 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的: ...

  9. [SDOI2015]序列统计(多项式快速幂)

    题目描述 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问 ...

随机推荐

  1. chrome审查元素功能,web开发强大帮手

    怎样打开Chrome的开发者工具? 你可以直接在页面上点击右键,然后选择审查元素: 或者在Chrome的工具中找到: 或者,你直接记住这个快捷方式: Ctrl+Shift+I (或者Ctrl+Shif ...

  2. 2018.09.15点名器(简单dp)

    描述 Ssoier在紧张的学习中,杜老师每天给他们传授精妙的知识. 杜老师为了活跃气氛,设计了一个点名器,这个点名器包含一个长度为M的数组(下标1开始),每个元素是一个oier的名字,每次点名的时候, ...

  3. 2018.08.17 洛谷[POI2010]GRA-The Minima Game(线性dp)

    传送门 短代码神奇dp. 自己yy的思路居然1A了好高兴啊! 不难想到每个人选择的时候一定是取连续的最大的那一段数,自然需要先排序. 然后可以用dp[i]表示当前最大数是a[i]的时候先手可以获得的最 ...

  4. 2018.08.10 atcoder No Need(线性dp)

    传送门 输入一个序列an" role="presentation" style="position: relative;">anan,输入k&q ...

  5. Linux Vim替换字符串的一些方法小结

    使用Linux环境 进行开发工作的程序猿经常有编辑器之争,是vim牛还是emacs棒.二者都是程序猿的开发神器,不管用好哪一个都会使你的工作事半功倍. 本文重点介绍 Vim的替换字符串方法技巧,这些方 ...

  6. web service 项目 和 普通 web项目 的 区别

    web service 面向的是开发者(需要再次开发) 普通web 面向的是用户(直接使用)

  7. jersey学习笔记

    最近一个项目用到了jersey,我只是负责前端.也借此机会好好了解一下REST webservice及一大推名词. http://redhacker.iteye.com/blog/1914105 1. ...

  8. window.open()用法说明

    1.例子 : window.open("index.jsp","_self"); window.open()格式: window.open( [sURL] [, ...

  9. 切勿用普通for循环遍历LinkedList

    ArrayList与LinkedList的普通for循环遍历 对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法: p ...

  10. eclipse快捷键(增加一些4连组合快捷键)

    http://www.blogjava.net/i369/articles/83309.html   ECLISPE的快捷键大全 Eclipse 常用快捷键收集2006年09月29日 星期五 12:0 ...