BZOJ 3684 大朋友和多叉树

Description

我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。

给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。

我们只需要知道答案关于\(950009857\)(\(453*2^{21}+1\),一个质数)取模后的值。

Input

第一行有\(2\)个整数\(s,m\)。

第二行有\(m\)个互异的整数,\(d[1],d[2],…,d[m]\),为集合\(D\)中的元素。

Output

输出一行仅一个整数,表示答案模\(950009857\)的值。

Sample Input

4 2

2 3

Sample Output

10


前置知识

\(\text{Lagrange}\)反演(金策的论文中有讲):

若两个没有常数项的函数\(f(x)\)和\(g(x)\)满足:

\[f(g(x))=x
\]

(也称这两个函数互为复合逆。)

我们就有:

\[[x^n]g(x)=\frac{1}{n}[w^{n-1}](\frac{w}{f(w)})^n
\]


设\(T(x)\)为答案的生成函数。

我们有:

\[T(x)=x+\sum_{i\in D}{T(x)}^i
\]

加上一个\(x\)是因为要考虑\(x\)为叶子的情况。

移项:

\[T(x)-\sum_{i\in D}{T(x)}^i=x
\]

设:

\[f(x)=x-\sum_{i\in D}x^i
\]

则:

\[f(T(x))=x\\
\Rightarrow [x^n]T(x)=\frac{1}{n}[w^{n-1}](\frac{w}{f(w)})^n
\]

\(\frac{w}{f(w)}\)上下约掉\(w\)后发现相当于将\(f(w)\)的每一项向左平移再求逆。

然后:

\[f(x)^k=\exp(k\ln(f(x)))
\]

代码:

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define N 100005
  4. using namespace std;
  5. inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
  6. const ll mod=950009857;
  7. ll ksm(ll t,ll x) {
  8. ll ans=1;
  9. for(;x;x>>=1,t=t*t%mod)
  10. if(x&1) ans=ans*t%mod;
  11. return ans;
  12. }
  13. ll NTT(ll *a,int d,int flag) {
  14. static int rev[N<<2];
  15. static int G=7;
  16. int n=1<<d;
  17. for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
  18. for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
  19. for(int s=1;s<=d;s++) {
  20. int len=1<<s,mid=len>>1;
  21. ll w=flag==1?ksm(G,(mod-1)/len):ksm(G,mod-1-(mod-1)/len);
  22. for(int i=0;i<n;i+=len) {
  23. ll t=1;
  24. for(int j=0;j<mid;j++,t=t*w%mod) {
  25. ll u=a[i+j],v=a[i+j+mid]*t%mod;
  26. a[i+j]=(u+v)%mod;
  27. a[i+j+mid]=(u-v+mod)%mod;
  28. }
  29. }
  30. }
  31. if(flag==-1) {
  32. ll inv=ksm(n,mod-2);
  33. for(int i=0;i<n;i++) a[i]=a[i]*inv%mod;
  34. }
  35. }
  36. void Inv(ll *inv,ll *a,int d) {
  37. static ll A[N<<2];
  38. if(!d) {
  39. inv[0]=ksm(a[0],mod-2);
  40. return ;
  41. }
  42. Inv(inv,a,d-1);
  43. for(int i=0;i<1<<d;i++) A[i]=a[i];
  44. for(int i=1<<d;i<1<<d+1;i++) A[i]=inv[i]=0;
  45. NTT(A,d+1,1),NTT(inv,d+1,1);
  46. for(int i=0;i<1<<d+1;i++) inv[i]=(2*inv[i]-inv[i]*inv[i]%mod*A[i]%mod+mod)%mod;
  47. NTT(inv,d+1,-1);
  48. for(int i=1<<d;i<1<<d+1;i++) inv[i]=0;
  49. }
  50. void Der(ll *ans,ll *a,int d) {
  51. int n=1<<d;
  52. for(int i=0;i<n-1;i++) ans[i]=a[i+1]*(i+1)%mod;
  53. ans[n-1]=0;
  54. }
  55. void Int(ll *ans,ll *a,int d) {
  56. int n=1<<d;
  57. for(int i=n-1;i;i--) ans[i]=a[i-1]*ksm(i,mod-2)%mod;
  58. ans[0]=0;
  59. }
  60. void Ln(ll *ln,ll *a,int d) {
  61. static ll inv[N<<2],der[N<<2];
  62. for(int i=0;i<1<<d+1;i++) inv[i]=der[i]=0;
  63. Inv(inv,a,d);Der(der,a,d);
  64. NTT(inv,d+1,1),NTT(der,d+1,1);
  65. for(int i=0;i<1<<d+1;i++) ln[i]=inv[i]*der[i]%mod;
  66. NTT(ln,d+1,-1);
  67. Int(ln,ln,d);
  68. for(int i=1<<d;i<1<<d+1;i++) ln[i]=0;
  69. }
  70. void Exp(ll *ex,ll *a,int d) {
  71. static ll A[N<<2],ln[N<<2];
  72. if(d==0) {
  73. ex[0]=1;
  74. return ;
  75. }
  76. Exp(ex,a,d-1);
  77. for(int i=0;i<1<<d+1;i++) A[i]=ln[i]=0;
  78. for(int i=0;i<1<<d;i++) A[i]=a[i];
  79. Ln(ln,ex,d);
  80. NTT(ln,d+1,1),NTT(A,d+1,1);
  81. NTT(ex,d+1,1);
  82. for(int i=0;i<1<<d+1;i++) ex[i]=ex[i]*(1-ln[i]+A[i]+mod)%mod;
  83. NTT(ex,d+1,-1);
  84. for(int i=1<<d;i<1<<d+1;i++) ex[i]=0;
  85. }
  86. ll A[N<<2],inv[N<<2],ln[N<<2],ex[N<<2];
  87. ll f[N<<2];
  88. int n,m;
  89. int main() {
  90. n=Get(),m=Get();
  91. int d=ceil(log2(n+1));
  92. for(int i=1;i<=m;i++) {
  93. int a=Get();
  94. f[a-1]=mod-1;
  95. }
  96. f[0]=1;
  97. Inv(inv,f,d);
  98. Ln(ln,inv,d);
  99. for(int i=0;i<1<<d;i++) ln[i]=ln[i]*n%mod;
  100. Exp(ex,ln,d);
  101. cout<<ex[n-1]*ksm(n,mod-2)%mod;
  102. return 0;
  103. }

BZOJ 3684 大朋友和多叉树的更多相关文章

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

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

  2. [BZOJ3684][拉格朗日反演+多项式求幂]大朋友和多叉树

    题面 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为\(1\)的结点是叶子结 ...

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

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

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

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

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

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

  6. 【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演

    这题一看就觉得是生成函数的题... 我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案. 根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$ ...

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

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

  8. [BZOJ 3652]大新闻

    [BZOJ 3652] 大新闻 题意 随机从 \([0,n)\) 中选取一个整数 \(x\), 并从 \([0,n)\) 中再选取一个整数 \(y\). 有 \(p\) 的概率选取一个能令 \(x\o ...

  9. P2008 大朋友的数字

    题目描述 有一批大朋友(年龄15岁以上),他们每人手上拿着一个数字,当然这个数字只有1位,也就是0到9之间.每个大朋友的分数为在他之前的最长不下降子序列中所有数之和.(这个序列必须以它作为结尾!)如有 ...

随机推荐

  1. SpringBoot入门教程(九)定时任务Schedule

    在日常项目运行中,我们总会有需求在某一时间段周期性的执行某个动作.比如每天在某个时间段导出报表,或者每隔多久统计一次现在在线的用户量.在springboot中可以有很多方案去帮我们完成定时器的工作,有 ...

  2. 使用mpvue开发小程序教程(一)

    前段时间,美团开源了mpvue这个项目,使得我们又多了一种用来开发小程序的框架选项.由于mpvue框架是完全基于Vue框架的(重写了其runtime和compiler),因此在用法上面是高度和Vue一 ...

  3. Maven教程(4)--Maven管理Oracle驱动包

    由于Oracle授权问题,Maven3不提供Oracle JDBC driver,为了在Maven项目中应用Oracle JDBC driver,必须手动添加到本地仓库. 手动添加到本地仓库需要本地有 ...

  4. C#多线程编程的同步也线程安全

    前一篇文章记录了简单的多线程编程的几种方式,但是在实际的项目中,也需要等待多线程执行完成之后再执行的方法,这个就叫做多线程的同步,或者,由于多个线程对同一对象的同时操作造成数据错乱,需要线程安全.这篇 ...

  5. Java Pom.xml 详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  6. 2019/1.6 Javascript Cookie

    cookie 就是一个1存放数据的东西,存储量很小(只有4KB),存放在客户端和应用设备上. 应用场景 用户注册,用户登录,购物车 chrome浏览器计算机存放cookie的位置 C:\Users\A ...

  7. JavaScript是如何工作的: Web推送通知的机制

    摘要: 如何在Web端推送消息? 这是专门探索 JavaScript 及其所构建的组件的系列文章的第9篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript是如何工作的:引擎,运行时 ...

  8. vue 组件通信

    组件 组件之间的数据是单向绑定的. 父组件向子组件通信 是通过子组件定义的props属性来实现.通过props定义变量与变量类型和验证方式. props简化定义 在简化定义中,变量是以数组的方式定义. ...

  9. Bootstrap方法之--排版、代码

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  10. 使用newtonsoft序列化

    如果将字符串序列化为datatable 时,字符串中包含null,序列化会报错,此时将datatabel 添加到dataset 中,在序列化成字符串,然后在将字符串反序列化成dataset