[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) 结尾 的 最长不下降子序列 的 和 (最长不下降子序 ...
随机推荐
- 原生ajax方法封装
/** * @function ajax request * @fields ajaxName:请求名称,method:请求方法,headers:setRequestHeader自定义部分,url:接 ...
- 如何用PhotoShop制作网站的favicon.ico
所谓favicon,即Favorites Icon的缩写,顾名思义,便是其可以让浏览器的收藏夹中除显示相应的标题外,还以图标的方式区别不同的网站.当然,这不仅仅是Favicon的全部,根据浏览器的不同 ...
- Ubuntu下安装LNMP之独立添加php扩展模块
使用php的过程中,发现某个扩展没有添加,又不想重新编译php,这个时候我们就需要单独添加需要的扩展模块. 下面以mysqli扩展模块为例,具体介绍安装步骤. 1.安装mysql 具体参考:Ubunt ...
- Leetcode 45. Jump Game II(贪心)
45. Jump Game II 题目链接:https://leetcode.com/problems/jump-game-ii/ Description: Given an array of non ...
- Spring学习--实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean
Spring 中有两种类型的 bean , 一种是普通的 bean , 另一种是工厂 bean , 即 FactroyBean. 工厂 bean 跟普通 bean 不同 , 其返回的对象不是指定类的一 ...
- 解决在ios下不能自动播放音频的问题
在ios下面是不允许自动播放音频这个操作的,不过我们可以使用微信提供的sdk来做到自动播放音乐的功能 wx.ready(()=>{}) 引入微信的sdk,之后在回调函数里面执行主动触发背景音乐播 ...
- [01]url请求到渲染
http状态码有哪些?分别表示什么意思?状态码告知从服务器返回的请求结果.2XX表明请求被正常处理了.200OK.204No Content(服务器接收的请求已经处理成功,但在返回的响应报文中不包含实 ...
- canvas知识01
本文转自:http://www.cnblogs.com/jsdarkhorse/archive/2012/06/29/2568451.html 更多参考:http://www.cnblogs.com/ ...
- O(n^2)以及O(nlogn)时间复杂度的排序算法
O(n^2)的算法 都是做的升序. 简单选择排序 思路:每次选择还未排序的区间的最小值和未排序区间的第一个值交换. function selectSort(arr){ for(let i = 0; i ...
- NOIP2016提高组D1T2 天天爱跑步
n<=300000个点的树,每个点有个人于第Ti秒观测,有m<=300000个人于时间0开始从Sj跑到Tj,速度1个点每秒,输出每个点上的人观察到的跑步的人的数量. 前25分:直接模拟每条 ...