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

题目连接php

题意

求知足以下条件的多叉树个数: 1.每个点的儿子个数在给定的集合 $S$ 内 2.总的叶子节点树为 $s$c++

儿子之间有顺序关系,但节点是没有标号的。函数

Sol

拉格朗日反演板子题。spa

(彷佛不像是个反演)code


拉格朗日反演:get

用来求 复合逆it

若是两个多项式 $F(x),G(x)$ 知足常数项均为 0,一次项均不为 0,而且 $G(F(x))=x$,那么称 $F(x)$ 与 $G(x)$ 互为复合逆(其实就是反函数)。 其中 $F(x)$ 和 $G(x)$ 能够互换。class

结论以下:二叉树

$$[x^n]F(x)=\frac{1}{n}[x^{-1}]\frac{1}{G^n(x)}$$static

证实工做及实际作法:

这个式子里怎么有 $x^{-1}$ 啊...听说是抽象代数里的,直接懵逼。

先无论这些,伪装咱们容许下标为负,先来随便乱推一下这个式子。

$$G(F(x))=x$$

$$\sum_{i=1}a_iF^i(x)=x$$

这里写成了形式幂级数的形式。 咱们两边对 $x$ 求导。

$$\sum_{i=1}ia_iF^{i-1}(x)F'(x)=1$$

两边同时除掉 $F^n(x)$,取 $[x^{-1}]$(我也不知道我在干什么) $$[x^{-1}]\sum_{i=1}ia_iF^{i-n-1}(x)F'(x)=[x^{-1}]\frac{1}{F^n(x)}$$

当 $i\neq n$ 时,$F^{i-n-1}(x)F'(x)=\dfrac{\big(F^{i-n}(x)\big)'}{i-n}$

求导后 $x^{-1}$ 项系数必定是 0。 因此只考虑 $i=n$ 的状况。

这时 $$F^{-1}(x)F'(x)=\dfrac{\sum_{i=1} ia_ix^{i-1}}{\sum_{i=1}a_ix^i}$$

$$F^{-1}(x)F'(x)=\dfrac{\sum_{i=1} ia_ix^{i-1}}{a_1x}·\dfrac{1}{1+\sum_{i=1}\frac{a_{i+1}}{a_1}x^i} $$

后面那个多项式可以求逆,它的逆的常数项显然为 1,所以不存在 $-1$ 次方项。 而前面那个多项式的 $[x^{-1}]$ 就是 : $\frac{a_1}{a_1}=1$ 因此 : $[x^{-1}] F^{-1}(x)F'(x)=1$

因此由以前的式子: $[x^{-1}]na_nF^{-1}(x)F'(x)=[x^{-1}]\frac{1}{F^n(x)}$

那么就证完了: $$a_n=\frac{1}{n}[x^{-1}]\frac{1}{F^n(x)}$$

可是咱们并无办法直接求解 $[x^{-1}]$,因此咱们能够把下标移动一下。 $$a_n=\frac{1}{n}[x^{n-1}]\frac{x^n}{F^n(x)}$$ 这里面乘了个 $x^n$,哪里来的 $x^{n-1}$ 系数啊,而后$F(x)$尚未逆我怎么求啊 $QAQ$

注意到 $F(x)$ 常数项为 $0$,而一次项不为 $0$

因而乎: $$a_n=\frac{1}{n}[x^{n-1}]\frac{1}{\big(\frac{F(x)}{x}\big)^n}$$ 这个好像就有 $x^{n-1}$了,并且还有逆,万事大吉。


回到本题,按照小朋友和二叉树的套路直接弄个生成函数。

设 $F(x)$ 是生成一棵含 $i$ 个叶子节点的合法的树的这个数列的生成函数 。

生成方式显然就是把一堆子树组合起来。 $$F(x)=x+\sum_{i\in S}F^i(x)$$ 枚举有几个儿子,注意这里咱们的下标表示的是叶子个数,因此后面的多项式不用乘上 $x$ 而且因为一个节点是一个叶子,应该给 $x^1$ 方项系数加 $1$

移个项:

$$F(x)-\sum_{i\in S}F^i(x)=x$$

发现复合函数! 令 $G(x)=x-\sum_{i\in S}x^i$ 那么: $$G(F(x))=x$$

咱们要求的是$F(x)$的第 $s$ 次方项系数而后就是套公式的事了。

什么你说你不想写 多项式快速幂 ?

注意到咱们是在 $bzoj$ 上进行评测,时间限制是总时间。 因此咱们直接写倍增快速幂就能在 $bzoj$ 上经过此题(OWO)。

#include<bits/stdc++.h>
#define Set(a,b) memset(a,b,sizeof(a))
#define Clear(a,_begin_,_end_) for(int i=_begin_;i<_end_;++i) a[i]=0
using namespace std;
const int N=1e5+10,MAXN=N<<2;
const int mod=950009857,phi=mod-1;
template <typename T> inline void init(T&x){
	x=0;char ch=getchar();bool t=0;
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
	if(t) x=-x;return;
}
typedef long long ll;
template<typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
template<typename T>inline void Dec(T&x,int y){x-=y;if(x <  0) x+=mod;return;}
template<typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
inline int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
inline int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
int rader[MAXN],wn[30],iwn[30],Inv[MAXN];
inline void Calc(){
	for(int i=0;i<30;++i) wn[i]=fpow(7,phi/(1<<i)),iwn[i]=fpow(wn[i],mod-2);
	Inv[1]=1;for(int i=2;i<MAXN;++i) Inv[i]=(ll)(mod-mod/i)*Inv[mod%i]%mod;return;
}
inline int Init(int n){int len=1,up=-1;while(len<=n)len<<=1,++up;for(int i=1;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);return len;}
inline void NTT(int*A,int n,int f){
	for(int i=1;i<n;++i) if(rader[i]>i) swap(A[i],A[rader[i]]);
	for(int i=1,h=1;i<n;++h,i<<=1){
		int W= (~f) ? wn[h]:iwn[h];
		for(int j=0,p=i<<1;j<n;j+=p)
			for(int w=1,k=0;k<i;++k,w=(ll)W*w%mod){
				int X=A[j|k],Y=(ll)w*A[j|k|i]%mod;
				A[j|k]=Sum(X,Y),A[j|k|i]=Dif(X,Y);
			}
	}if(!~f) for(int i=0;i<n;++i) A[i]=(ll)A[i]*Inv[n]%mod;
}
int n,m;
inline void Poly_Inv(int*F,int*I,int n){
	if(n==1) {I[0]=1;return;}
	Poly_Inv(F,I,(n+1)>>1);int len=Init(n<<1);
	static int A[MAXN];for(int i=0;i<n;++i) A[i]=F[i];Clear(A,n,len);
	NTT(A,len,1);NTT(I,len,1);
	for(int i=0;i<len;++i) I[i]=Dif(2ll*I[i]%mod,(ll)I[i]*I[i]%mod*A[i]%mod);
	NTT(I,len,-1);Clear(I,n,len);return;
}
int main()
{
	Calc();init(n),init(m);
	static int A[MAXN],G[MAXN];int x;
	for(int i=1;i<=m;++i) init(x),A[x-1]=phi;A[0]=1;
	int k=n;G[0]=1;int len=Init(n<<1);
	while(k) {
		NTT(A,len,1);
		if(k&1) {
			NTT(G,len,1);
			for(int i=0;i<len;++i) G[i]=(ll)G[i]*A[i]%mod;
			NTT(G,len,-1);Clear(G,n,len);
		}
		for(int i=0;i<len;++i) A[i]=(ll)A[i]*A[i]%mod;
		NTT(A,len,-1);Clear(A,n,len);k>>=1;
	}
	Set(A,0);Poly_Inv(G,A,n);
	int ans=(ll)A[n-1]*Inv[n]%mod;
	cout<<ans<<endl;
	return 0;
}
相关文章
相关标签/搜索