【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$。
然后后面就是多项式快速幂了。
- #include<bits/stdc++.h>
- #define G 7
- #define L long long
- #define MOD 950009857
- #define inv(x) pow_mod(x,MOD-2)
- #define M 1<<18
- using namespace std;
- L pow_mod(L x,L k){
- L ans=;
- while(k){
- if(k&) ans=ans*x%MOD;
- k=k>>; x=x*x%MOD;
- }
- return ans;
- }
- void change(L a[],int n){
- for(int i=,j=;i<n-;i++){
- if(i<j) swap(a[i],a[j]);
- int k=n>>;
- while(j>=k) j-=k,k>>=;
- j+=k;
- }
- }
- void NTT(L a[],int n,int on){
- change(a,n);
- for(int h=;h<=n;h<<=){
- L wn=pow_mod(G,(MOD-)/h);
- for(int j=;j<n;j+=h){
- L w=;
- for(int k=j;k<j+(h>>);k++){
- L u=a[k],t=a[k+(h>>)]*w%MOD;
- a[k]=(u+t)%MOD;
- a[k+(h>>)]=(u-t+MOD)%MOD;
- w=w*wn%MOD;
- }
- }
- }
- if(on==-){
- L inv=inv(n);
- for(int i=;i<n;i++) a[i]=a[i]*inv%MOD;
- reverse(a+,a+n);
- }
- }
- void getinv(L a[],L b[],int n){
- if(n==) return void(b[]=inv(a[]));
- static L A[M],B[M];
- memset(A,,sizeof(A)); memset(B,,sizeof(B));
- getinv(a,B,n>>);
- for(int i=;i<n;i++) A[i]=a[i];
- NTT(A,n<<,); NTT(B,n<<,);
- for(int i=;i<(n<<);i++) b[i]=(*B[i]-A[i]*B[i]%MOD*B[i]%MOD+MOD)%MOD;
- NTT(b,n<<,-);
- for(int i=;i<n;i++) b[n+i]=;
- }
- void qiudao(L a[],L b[],int n){
- memset(b,,sizeof(b));
- for(int i=;i<n;i++) b[i-]=i*a[i]%MOD;
- }
- void jifen(L a[],L b[],int n){
- memset(b,,sizeof(b));
- for(int i=;i<n;i++) b[i+]=a[i]*pow_mod(i+,MOD-)%MOD;
- }
- void getln(L a[],L b[],int n){
- static L c[M],d[M];
- memset(c,,M<<); memset(d,,M<<);
- qiudao(a,c,n); getinv(a,d,n);
- NTT(c,n<<,); NTT(d,n<<,);
- for(int i=;i<(n<<);i++) c[i]=c[i]*d[i]%MOD;
- NTT(c,n<<,-);
- jifen(c,b,n);
- }
- void getexp(L a[],L b[],int n){
- if(n==){b[]=; return;}
- static L lnb[M]; memset(lnb,,M<<);
- getexp(a,b,n>>); getln(b,lnb,n);
- for(int i=;i<n;i++) lnb[i]=(a[i]-lnb[i]+MOD)%MOD;
- lnb[n]=;
- lnb[]=(lnb[]+)%MOD;
- NTT(lnb,n<<,); NTT(b,n<<,);
- for(int i=;i<(n<<);i++) b[i]=b[i]*lnb[i]%MOD;
- NTT(b,n<<,-);
- for(int i=;i<n;i++) b[i+n]=;
- }
- L g[M]={},f[M]={};
- void pow_mod(L a[],L b[],int n,int k){
- memset(b,,M<<);
- getln(a,b,n);
- for(int i=;i<n;i++) a[i]=b[i]*k%MOD;
- memset(b,,M<<);
- getexp(a,b,n);
- }
- int main(){
- int n,m;
- scanf("%d%d",&n,&m);
- for(int i=;i<=m;i++){
- int x; scanf("%d",&x);
- g[x-]=-;
- }
- g[]=;
- int nn=;while(nn<n) nn<<=;
- getinv(g,f,nn);
- memset(g,,sizeof(g));
- pow_mod(f,g,nn,n);
- L ans=inv(n)*g[n-]%MOD;
- cout<<ans<<endl;
- }
【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演的更多相关文章
- BZOJ3684 大朋友和多叉树(多项式相关计算)
设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数.不难得出$f(x)=\sum_{k\in D}f(x)^k+x$我们要求这个多项式的第$n$项,由拉格朗日反演可得$[x ...
- [BZOJ3684]大朋友和多叉树
设答案为$f_s$,它的生成函数为$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i\end{align*}$,则我们有$\begin{align* ...
- 【xsy2479】counting 生成函数+多项式快速幂
题目大意:在字符集大小为$m$的情况下,有多少种构造长度为$n$的字符串$s$的方案,使得$C(s)=k$.其中$C(s)$表示字符串$s$中出现次数最多的字符的出现次数. 对$998244353$取 ...
- bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)
题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...
- BZOJ3992 [SDOI2015]序列统计 【生成函数 + 多项式快速幂】
题目 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问题 ...
- BZOJ 3684: 大朋友和多叉树 [拉格朗日反演 多项式k次幂 生成函数]
3684: 大朋友和多叉树 题意: 求有n个叶子结点,非叶节点的孩子数量\(\in S, a \notin S\)的有根树个数,无标号,孩子有序. 鏼鏼鏼! 树的OGF:\(T(x) = \sum_{ ...
- 【BZOJ3684】大朋友和多叉树(拉格朗日反演)
题目链接 题意 求满足如下条件的多叉树个数: 1.每一个点的儿子个数在给定的集合 \(S\) 内 2.总的叶子节点树为 \(s\) 儿子之间有顺序关系,但节点是没有标号的. Sol 拉格朗日反演板子题 ...
- BZOJ 3684 大朋友和多叉树
BZOJ 3684 大朋友和多叉树 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的: ...
- [SDOI2015]序列统计(多项式快速幂)
题目描述 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问 ...
随机推荐
- chrome审查元素功能,web开发强大帮手
怎样打开Chrome的开发者工具? 你可以直接在页面上点击右键,然后选择审查元素: 或者在Chrome的工具中找到: 或者,你直接记住这个快捷方式: Ctrl+Shift+I (或者Ctrl+Shif ...
- 2018.09.15点名器(简单dp)
描述 Ssoier在紧张的学习中,杜老师每天给他们传授精妙的知识. 杜老师为了活跃气氛,设计了一个点名器,这个点名器包含一个长度为M的数组(下标1开始),每个元素是一个oier的名字,每次点名的时候, ...
- 2018.08.17 洛谷[POI2010]GRA-The Minima Game(线性dp)
传送门 短代码神奇dp. 自己yy的思路居然1A了好高兴啊! 不难想到每个人选择的时候一定是取连续的最大的那一段数,自然需要先排序. 然后可以用dp[i]表示当前最大数是a[i]的时候先手可以获得的最 ...
- 2018.08.10 atcoder No Need(线性dp)
传送门 输入一个序列an" role="presentation" style="position: relative;">anan,输入k&q ...
- Linux Vim替换字符串的一些方法小结
使用Linux环境 进行开发工作的程序猿经常有编辑器之争,是vim牛还是emacs棒.二者都是程序猿的开发神器,不管用好哪一个都会使你的工作事半功倍. 本文重点介绍 Vim的替换字符串方法技巧,这些方 ...
- web service 项目 和 普通 web项目 的 区别
web service 面向的是开发者(需要再次开发) 普通web 面向的是用户(直接使用)
- jersey学习笔记
最近一个项目用到了jersey,我只是负责前端.也借此机会好好了解一下REST webservice及一大推名词. http://redhacker.iteye.com/blog/1914105 1. ...
- window.open()用法说明
1.例子 : window.open("index.jsp","_self"); window.open()格式: window.open( [sURL] [, ...
- 切勿用普通for循环遍历LinkedList
ArrayList与LinkedList的普通for循环遍历 对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法: p ...
- eclipse快捷键(增加一些4连组合快捷键)
http://www.blogjava.net/i369/articles/83309.html ECLISPE的快捷键大全 Eclipse 常用快捷键收集2006年09月29日 星期五 12:0 ...