[BZOJ3684]大朋友和多叉树
设答案为$f_s$,它的生成函数为$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i\end{align*}$,则我们有$\begin{align*}F(x)=x+\sum\limits_{k\in D}F^k(x)\end{align*}$(枚举儿子数量$k$,计数$k$个儿子的权值组合起来的方案,再加上单点成树的情况),移项得到$\begin{align*}F(x)-\sum\limits_{k\in D}F^k(x)=x\end{align*}$,再设$\begin{align*}G(x)=x-\sum\limits_{k\in D}x^k\end{align*}$,则$G(F(x))=x$,也就是说它们互为反函数
现在问题转化为:我们已经知道了$G(x)$,要求$F(x)$使得$G(F(x))=x$,也就是求$G$的复合逆,我们可以用拉格朗日反演求出$F$
拉格朗日反演:若$g(f(x))=x$,则$[x^n]f(x)=\dfrac1n[x^{-1}]\dfrac1{g^n(x)}$,实际使用更多用$\dfrac1n[x^{n-1}]\left(\dfrac x{g(x)}\right)^n$
证明(思路来自zjt的博客和被zjt钦点比较靠谱的博客,这里的证明并不严谨):
$g(f(x))=x\Rightarrow f(g(x))=x$,记$f(x)=\sum\limits_{i=0}^\infty a_ix^i$
$\begin{align*}f(g(x))&=x\\\sum\limits_{i=0}^\infty a_ig^i(x)&=x\\\sum\limits_{i=1}^\infty ia_ig^{i-1}(x)g'(x)&=1\\\sum\limits_{i=1}^\infty ia_ig^{i-1-n}(x)g'(x)&=\dfrac1{g^n(x)}\\ [x^{-1}]\left(na_n\dfrac{g'(x)}{g(x)}+\sum\limits_{\substack{i\geq1\\i\ne n}}ia_i\dfrac1{i-n}\left(g^{i-n}(x)\right)'\right)&=[x^{-1}]\dfrac1{g^n(x)}\end{align*}$
因为幂级数求导之后不会出现$x^{-1}$的项,所以sigma后面全是$0$,即$\begin{align*}[x^{-1}]na_n\dfrac{g'(x)}{g(x)}=[x^{-1}]\dfrac1{g^n(x)}\end{align*}$
设$\begin{align*}g(x)=\sum\limits_{i=1}^\infty b_ix^i\end{align*},z=\sum\limits_{i=1}^\infty\frac{b_{i+1}}{b_1}x^i$(为了方便求复合逆,我们需要硬点$g$没有常数项)
$\begin{align*}\dfrac{g'(x)}{g(x)}&=\dfrac{\sum\limits_{i=1}^\infty ib_ix^{i-1}}{\sum\limits_{i=1}^\infty b_ix^i}\\&=\dfrac{\sum\limits_{i=1}^\infty ib_ix^{i-1}}{b_1x}\dfrac1{1+z}\\&=\left(x^{-1}+\sum\limits_{i=2}^\infty\dfrac{ib_ix^{i-2}}{b_1}\right)\sum\limits_{i=0}^\infty(-1)^iz^i\end{align*}$
左边的sigma全是次数大于$-1$的项,右边的sigma包含一个$1$,其他都是次数大于$-1$的项,所以$[x^{-1}]\dfrac{g'(x)}{g(x)}=1$,从这里也可以看出我们要限制$g$的一次项不为$0$才能方便地求出复合逆
最后我们得到$na_n=[x^{-1}]\dfrac1{g^n(x)}$,即$a_n=\dfrac1n[x^{-1}]\dfrac1{g^n(x)}$
有了这个定理,我们可以用多项式求逆+快速幂在$O(n\log_2^2n)$的时间内求出$f_n$
这个时间复杂度是不是不太优秀啊==其实我们还有更优秀的方法
对于一个多项式$A(x)$,我们要求$B=A^k$,能把指数拿下来的运算就只有对数了,所以我们有$\ln B=k\ln A$,再求个指数,我们就得到了$B$,也就是$B=e^{k\ln A}$
为求多项式exp,我们需要一个前置技能:多项式的牛顿迭代
已知$g(x)$,要求$f(x)$使得$g(f(x))=0$
倍增,假设已经求出$g(f_0(x))\equiv0(\text{mod }x^{\frac n2})$,我们要求$g(f(x))\equiv0(\text{mod }x^n)$,我们可以把$g(f(x))$在$f_0(x)$处泰勒展开,即$\begin{align*}g(f(x))&=\sum\limits_{i=0}^\infty\dfrac{g^{(i)}(f_0(x))}{i!}(f(x)-f_0(x))^i\end{align*}$
注意到从$f_0(x)$变化到$f(x)$,我们加入次数$\geq\dfrac n2$的项不会改变模$x^{\frac n2}$为$0$这个性质,还可以调整在模$x^n$意义下的值,所以我们可以找到一个$f(x)$使得它的前$\dfrac n2$项系数和$f_0(x)$一样,也就是$f(x)-f_0(x)\equiv0(\text{mod }x^{\frac n2})$,这导致$(f(x)-f_0(x))^i(i\geq2)$在模$x^n$意义下都为$0$,所以$g(f(x))\equiv g(f_0(x))+g'(f_0(x))(f(x)-f_0(x))(\text{mod }x^n)$,即$f(x)\equiv f_0(x)-\dfrac{g(f(x))}{g'(f(x))}(\text{mod }x^n)$
这个式子本身没有太大用处,但我们来看看当$g(x)$变成具体的东西时这个式子会带来什么神奇的效应
多项式exp:已知$f(x)$,要求$g(x)=e^{f(x)}$
上式即$\ln g(x)-f(x)=0$,令$h(g(x))=\ln g(x)-f(x)$,我们要找到一个$g(x)$使$h(g(x))=0$
套用牛顿迭代的式子,用倍增求$g$,$g(x)=g_0(x)-\dfrac{h(g_0(x))}{h'(g_0(x))}$,因为$h(g(x))=\ln g(x)-f(x),h'(g(x))=\dfrac1{g(x)}$,所以$g(x)=g_0(x)-g_0(x)(\ln g_0(x)-f(x))=g_0(x)(1-\ln g_0(x)+f(x))$,于是每次多项式求对数和FFT即可,时间复杂度还是$O(n\log_2n)$
于是我们就可以在$O(n\log_2n)$的时间内求多项式快速幂啦~
于是整道题就做完了,是不是很愉♂悦啊
全家桶真好玩
#include<stdio.h>
#include<string.h>
const int mod=950009857;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int pow(int a,int b){
int s=1;
while(b){
if(b&1)s=mul(s,a);
a=mul(a,a);
b>>=1;
}
return s;
}
int rev[300010],N,iN;
void pre(int n){
int i,k;
for(N=1,k=0;N<n;N<<=1)k++;
for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
iN=pow(N,mod-2);
}
void swap(int&a,int&b){a^=b^=a^=b;}
void ntt(int*a,int on){
int i,j,k,t,w,wn;
for(i=0;i<N;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(i=2;i<=N;i<<=1){
wn=pow(7,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
for(j=0;j<N;j+=i){
w=1;
for(k=0;k<i>>1;k++){
t=mul(w,a[i/2+j+k]);
a[i/2+j+k]=de(a[j+k],t);
a[j+k]=ad(a[j+k],t);
w=mul(w,wn);
}
}
}
if(on==-1){
for(i=0;i<N;i++)a[i]=mul(a[i],iN);
}
}
int t0[300010];
void getinv(int*a,int*b,int n){
if(n==1){
b[0]=pow(a[0],mod-2);
return;
}
int i;
getinv(a,b,n>>1);
pre(n<<1);
memset(t0,0,sizeof(t0));
for(i=0;i<n;i++)t0[i]=a[i];
ntt(t0,1);
ntt(b,1);
for(i=0;i<N;i++)b[i]=mul(b[i],2-mul(b[i],t0[i]));
ntt(b,-1);
for(i=n;i<N;i++)b[i]=0;
}
int t1[300010],inv[300010];
void getln(int*a,int*b,int n){
int i;
memset(t1,0,sizeof(t1));
getinv(a,t1,n);
for(i=1;i<n;i++)b[i-1]=mul(i,a[i]);
ntt(b,1);
ntt(t1,1);
for(i=0;i<N;i++)b[i]=mul(b[i],t1[i]);
ntt(b,-1);
for(i=n-1;i>0;i--)b[i]=mul(b[i-1],inv[i]);
b[0]=0;
for(i=n;i<N;i++)b[i]=0;
}
int t2[300010];
void exp(int*a,int*b,int n){
if(n==1){
b[0]=1;
return;
}
int i;
exp(a,b,n>>1);
memset(t2,0,sizeof(t2));
getln(b,t2,n);
for(i=0;i<n;i++)t2[i]=de(a[i],t2[i]);
t2[0]++;
ntt(b,1);
ntt(t2,1);
for(i=0;i<N;i++)b[i]=mul(b[i],t2[i]);
ntt(b,-1);
for(i=n;i<N;i++)b[i]=0;
}
int t3[300010];
void pow(int*a,int k,int*b,int n){
int i;
memset(t3,0,sizeof(t3));
getln(a,t3,n);
for(i=0;i<n;i++)t3[i]=mul(t3[i],k);
exp(t3,b,n);
}
int a[300010],b[300010];
#define N 300000
int main(){
int n,m,i,x;
inv[1]=1;
for(i=2;i<=N;i++)inv[i]=mul(mod/i,-inv[mod%i]);
scanf("%d%d",&n,&m);
for(i=0;i<m;i++){
scanf("%d",&x);
a[x-1]=-1;
}
a[0]=1;
for(m=1;m<n;m<<=1);
getinv(a,b,m);
memset(a,0,sizeof(a));
pow(b,n,a,m);
printf("%d",(mul(a[n-1],inv[n])+mod)%mod);
}
[BZOJ3684]大朋友和多叉树的更多相关文章
- BZOJ3684 大朋友和多叉树(多项式相关计算)
设$f(x)$为树的生成函数,即$x^i$的系数为根节点权值为$i$的树的个数.不难得出$f(x)=\sum_{k\in D}f(x)^k+x$我们要求这个多项式的第$n$项,由拉格朗日反演可得$[x ...
- bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)
题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...
- BZOJ 3684: 大朋友和多叉树 [拉格朗日反演 多项式k次幂 生成函数]
3684: 大朋友和多叉树 题意: 求有n个叶子结点,非叶节点的孩子数量\(\in S, a \notin S\)的有根树个数,无标号,孩子有序. 鏼鏼鏼! 树的OGF:\(T(x) = \sum_{ ...
- BZOJ 3684 大朋友和多叉树
BZOJ 3684 大朋友和多叉树 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的: ...
- [BZOJ3684][拉格朗日反演+多项式求幂]大朋友和多叉树
题面 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为\(1\)的结点是叶子结 ...
- 【BZOJ3684】大朋友和多叉树(拉格朗日反演)
题目链接 题意 求满足如下条件的多叉树个数: 1.每一个点的儿子个数在给定的集合 \(S\) 内 2.总的叶子节点树为 \(s\) 儿子之间有顺序关系,但节点是没有标号的. Sol 拉格朗日反演板子题 ...
- 【bzoj3684】 大朋友和多叉树 生成函数+多项式快速幂+拉格朗日反演
这题一看就觉得是生成函数的题... 我们不妨去推下此题的生成函数,设生成函数为$F(x)$,则$[x^s]F(x)$即为答案. 根据题意,我们得到 $F(x)=x+\sum_{i∈D} F^i(x)$ ...
- P2008 大朋友的数字
题目描述 有一批大朋友(年龄15岁以上),他们每人手上拿着一个数字,当然这个数字只有1位,也就是0到9之间.每个大朋友的分数为在他之前的最长不下降子序列中所有数之和.(这个序列必须以它作为结尾!)如有 ...
- 洛谷 P2008 大朋友的数字
DP,动态规划 树状数组 最长不下降子序列 by GeneralLiu 题目 就是说给一串由 0~9 组成的序列 求 以 i (1~n) 结尾 的 最长不下降子序列 的 和 (最长不下降子序 ...
随机推荐
- 浅析JavaScript的垃圾回收机制
JavaScript语言是一门优秀的脚本语言.其中包含脚本语言的灵活性外还拥有许多高级语言的特性.例如充许构建和实例化一个对象,垃圾回收机制(GC:Garbage Collecation).通常我们使 ...
- [ZJOI2007]棋盘制作 (单调栈)
[ZJOI2007]棋盘制作 题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8 \times 88×8大小的黑白相间 ...
- 在eclipse中从gitlab上面下载项目
(1)在eclipse中 import --git--uri--输入用户名密码,下载,这个时候是在本地建立了一个本地仓库 (2)把仓库中的项目导入到eclipse的工作空间中. (3)将所需要的项目转 ...
- mycat 管理MySQL5.7主从搭建
1.首先安装MySQL ab: 192.168.6.163 master 192.168.6.167 slave master: vi /etc/opt/rh/rh-mysql57/my.cnf.d/ ...
- rsync安装使用详解
rsync是类unix系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync.它的特性如下: 可以镜像保存整个目录树和文件系统. 可以很容易做到保持原来文件的权限.时间.软硬 ...
- linux 服务器下入侵之后的日志清理
1.web日志的清理:access.log 和auth.log 位置在/var/log/下面. 2.系统日志存放在:/root/.bash_history
- iconfont字体图标
1.1.进入阿里图标网站 http://www.iconfont.cn/ 1.2.在购物车里添加自己需要的字体图标 1.3.下载代码 1.4.解压过后,找到iconfont.css,放在你的项目里,需 ...
- 着色方案(bzoj 1079)
Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木 ...
- HDU1025---(LIS 最长上升子序列 的应用)
分析: n行 每行包含两个整数p r;意思是p从到r 不能有交叉的路 p刚好从1->n, 可看做下标,到的地方看做值 就转化为了最长上升子序列的问题 此题难点,怎么将其转化为LIS问题 #inc ...
- 【BZOJ3132】上帝造题的七分钟 [树状数组]
上帝造题的七分钟 Time Limit: 20 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description “第一分钟,X说,要有矩阵 ...