BZOJ3684 大朋友和多叉树(多项式相关计算)
设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数。
不难得出$f(x)=\sum_{k\in D}f(x)^k+x$
我们要求这个多项式的第$n$项,由拉格朗日反演可得
$[x^n]f(x)=\frac1n[x^{n-1}](\frac x{g(x)})^n$
其中$[x^n]f(x)$表示$f(x)$的$n$次项系数。
$f(x)$是$g(x)$的复合逆,即$g(f(x))=x$
在本题中,$g(x)=x-\sum_{k\in D}x^k$
我们需要多项式求逆和多项式快速幂。
多项式求逆就不介绍了,多项式快速幂一种朴素的做法是倍增+NTT,复杂度是$O(n\log n\log k)$
有没有更快的做法呢?
观察到$f(x)^n=e^{n\ln(f(x))}$,所以我们只需要快速算$\ln(f(x))$及$e^{f(x)}$即可。
注意$f(x)$的常数项要为1,还好出题人良心保证了这一点。
Part 1:如何算$\ln(f(x))$?
设$g(x)=\ln(f(x))$,那么$g'(x)=\frac{f'(x)}{f(x)}$,所以$g(x)=\int\frac{f'(x)}{f(x)}$,时间复杂度$O(n\log n)$
Part 2:如何算$e^{f(x)}$?
还是考虑倍增,假设我已经求出$g_0(x)=e^{f(x)}(mod\;x^n)$,要求$g(x)=e^{f(x)}(mod\;x^{2n})$
根据泰勒展开,有$$0=h(g(x))=\sum_{i=0}^{\infty}\frac{h^{(i)}(g_0(x))}{i!}(g(x)-g_0(x))^i$$当$i>1$时,上式$mod\;x^{2n}$为$0$
所以$0=h(g_0(x))+h'(g_0(x))(g(x)-g_0(x))\;(mod\;x^{2n})$
即$g(x)=g_0(x)-\frac{h(g_0(x))}{h'(g_0(x))}(mod\;x^{2n})$
其中$h(g(x))=\ln(g(x))-f(x)$
所以$g(x)=g_0(x)-\frac{\ln(g_0(x))-f(x)}{\frac 1{g_0(x)}}=g_0(x)(1-\ln(g_0(x))+f(x))\;(mod\;x^{2n})$
时间复杂度$O(n\log n)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define pre m=n<<1; for(int i=0;i<m;i++) r[i]=(r[i>>1]>>1)|((i&1)<<l) typedef long long ll;
const int p=,N=;
int n,m,l,x,nn,f[N],g[N],t1[N],t2[N],t3[N],r[N],ni[N];
ll pw(ll a,int b) {ll r=; for(;b;b>>=,a=a*a%p) if(b&) r=r*a%p; return r;} void ntt(int *a,int n,int f) {
for(int i=;i<n;i++) if(r[i]>i) std::swap(a[i],a[r[i]]);
for(int i=;i<n;i<<=)
for(int j=,wn=pw(,((p-)/(i*)*f+p-)%(p-));j<n;j+=i<<)
for(int k=,w=;k<i;k++,w=(ll)w*wn%p) {
int x=a[j+k],y=(ll)a[j+k+i]*w%p;
a[j+k]=(x+y)%p,a[j+k+i]=(x-y+p)%p;
}
if(!~f) for(int i=;i<n;i++) a[i]=(ll)a[i]*ni[n]%p;
}
void inv(int *f,int *g,int *t,int n,int l) {
if(n==) {g[]=pw(f[],p-); return;}
inv(f,g,t,n>>,l-),memcpy(t,f,sizeof(int)*n),memset(t+n,,sizeof(int)*n),pre;ntt(t,m,),ntt(g,m,);
for(int i=;i<m;i++) g[i]=(ll)g[i]*(-(ll)t[i]*g[i]%p+p)%p;
ntt(g,m,-),memset(g+n,,sizeof(int)*n);
}
void ln(int *f,int *g,int *t,int n,int l) {
memset(t,,sizeof(int)*n*),inv(f,t,t1,n,l);
for(int i=;i+<n;i++) g[i]=(ll)f[i+]*(i+)%p;
pre;ntt(g,m,),ntt(t,m,);
for(int i=;i<m;i++) g[i]=(ll)g[i]*t[i]%p;
ntt(g,m,-);
for(int i=m-;i;i--) g[i]=(ll)g[i-]*ni[i]%p;
g[]=,memset(g+n,,sizeof(int)*n);
}
void ex(int *f,int *g,int *t,int n,int l) {
if(n==) {g[]=; return;}
ex(f,g,t,n>>,l-),memset(t,,sizeof(int)*n*),ln(g,t,t2,n,l);
for(int i=;i<n;i++) t[i]=(f[i]-t[i]+p)%p;
t[]=(t[]+)%p,pre;ntt(t,m,),ntt(g,m,);
for(int i=;i<m;i++) g[i]=(ll)g[i]*t[i]%p;
ntt(g,m,-),memset(g+n,,sizeof(int)*n);
} int main() {
scanf("%d%d",&n,&m),f[]++,ni[]=,nn=n;
for(int i=;i<=m;i++) scanf("%d",&x),f[x-]=p-;
for(m=n,n=,l=;n<=m;n<<=) l++;
for(int i=;i<=n*;i++) ni[i]=(ll)(p-p/i)*ni[p%i]%p;
inv(f,g,t1,n,l),memset(f,,sizeof f),ln(g,f,t2,n,l);
for(int i=;i<n;i++) f[i]=(ll)f[i]*nn%p;
memset(g,,sizeof g),ex(f,g,t3,n,l),printf("%lld",(ll)g[nn-]*ni[nn]%p);
return ;
}
BZOJ3684 大朋友和多叉树(多项式相关计算)的更多相关文章
- bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)
题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...
- [BZOJ3684]大朋友和多叉树
设答案为$f_s$,它的生成函数为$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i\end{align*}$,则我们有$\begin{align* ...
- BZOJ 3684: 大朋友和多叉树 [拉格朗日反演 多项式k次幂 生成函数]
3684: 大朋友和多叉树 题意: 求有n个叶子结点,非叶节点的孩子数量\(\in S, a \notin S\)的有根树个数,无标号,孩子有序. 鏼鏼鏼! 树的OGF:\(T(x) = \sum_{ ...
- BZOJ 3684 大朋友和多叉树
BZOJ 3684 大朋友和多叉树 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的: ...
- [BZOJ3684][拉格朗日反演+多项式求幂]大朋友和多叉树
题面 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为\(1\)的结点是叶子结 ...
- 【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题... 我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案. 根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$ ...
- 【BZOJ3684】大朋友和多叉树(拉格朗日反演)
题目链接 题意 求满足如下条件的多叉树个数: 1.每一个点的儿子个数在给定的集合 \(S\) 内 2.总的叶子节点树为 \(s\) 儿子之间有顺序关系,但节点是没有标号的. Sol 拉格朗日反演板子题 ...
- 【learning】多项式相关(求逆、开根、除法、取模)
(首先要%miskcoo,这位dalao写的博客(这里)实在是太强啦qwq大部分多项式相关的知识都是从这位dalao博客里面学的,下面这篇东西是自己对其博客学习后的一些总结和想法,大部分是按照其博客里 ...
- P2008 大朋友的数字
题目描述 有一批大朋友(年龄15岁以上),他们每人手上拿着一个数字,当然这个数字只有1位,也就是0到9之间.每个大朋友的分数为在他之前的最长不下降子序列中所有数之和.(这个序列必须以它作为结尾!)如有 ...
随机推荐
- 2017北京国庆刷题Day4 morning
期望得分:0+40+30=70 实际得分:0+10+10=20 题目修改:只能由0变1,只能用一次操作 大模拟 #include<cstdio> #include<cstring&g ...
- ExtJs6级联combo的实现
父类获取子类进行操作 { xtype: 'combo', store: Common.Dic.getDicData("IMAGE_BIG_TYPE") , multiSelect: ...
- php的set_time_limit()函数
set_time_limit(0); 括号里边的数字是执行时间,如果为零说明永久执行直到程序结束,如果为大于零的数字,则不管程序是否执行完成,到了设定的秒数,程序结束. 一个简单的例子,在网页里显示1 ...
- 关于PHP7
目前一直使用php7也看了许多文档视频等,整理一下相关细节(仅为记录-),对于PHP7性能,如下图所示. * 在wordpress3.0.1中 php7比php5.6性能提升约3倍左右 新特性 一.变 ...
- 使用location.href跳转页面在火狐浏览器中报错404
HTML文件中引入外部js文件,在该js文件里用window.location.href跳转相对路径下的html地址,火狐浏览器会报错404,而谷歌浏览器却显示正常·,分析了一下原因:在识别相对路径时 ...
- Spring Security 入门(1-4-1)Spring Security - 认证过程
理解时可结合一下这位老兄的文章:http://www.importnew.com/20612.html 1.Spring Security的认证过程 1.1.登录过程 - 如果用户直接访问登录页面 用 ...
- Celery 分布式任务队列快速入门
Celery 分布式任务队列快速入门 本节内容 Celery介绍和基本使用 在项目中如何使用celery 启用多个workers Celery 定时任务 与django结合 通过django配置cel ...
- sys.exc_info()可以捕获到任意异常
import sys try: a = 3 assert a > 4 except: exc = sys.exc_info()#返回异常的元祖 print (exc)
- java 面向对象编程。。。。
经过一周的学习(java),总结了许多,对java的理解,java的类型,运用,安装,基础语法,变量,常量,表达式,语句 java从C语言中继承了大量语言特性.java面向对象编程的基本特征,包括继承 ...
- zookeeper初探
安装三台linux虚拟机,安装好java环境,并配置好网络以及host文件,分别改好hostname为node0.node1.node2 上传下载好的zookeeper文件到node0的/usr/lo ...