拉格朗日反演可以互推一对多项式复合逆,拉反通常起到将函数自、因变量交换,简化柿子的作用。

定义

  • 复合逆:\(F(G(x))\equiv G(F(x))\equiv x\pmod {x^n}\)
    则称\(F\)\(G\)互为复合逆,记作\(G(x)=F^{(-1)}(x)\)

  • 引理:\([x^{-1}]F^k(x)F'(x)=[k=-1]\)

证明 当$k\ne-1$,有$F'(x)F(x)^k=(\frac{1}{k+1}F(x){k+1})'$,是整式显然无$[x^{-1}]$项;

\(k=-1\),有\([x^{-1}]\frac{F'(x)}{F(x)}=[x^0]\frac{F'(x)}{F(x)/x}\) 上下的常数项均为\([x^1]F(x)\)所以值为\(1\)

  • 拉格朗日反演:若\(G(F(x))=x\),且满足常数项为\(0\),一次项可逆,则\([x^n]G^k(x)=\dfrac{k}{n}[x^{-k}]F^{-n}(x)=\dfrac{k}{n}[x^{n-k}](\dfrac{x}{F(x)})^n\)

通常使用最右边形式,因为要常数项可逆。

证明 $G^k(F(x))=x^k$

两侧求导得: \((G^k)'(F(x))F'(x)=(\sum\limits_{i}i([x^i]G^k)F^{i-1})F'(x)=kx^{k-1}\)

同除\(F^n(x)\)得:\(\sum\limits_{i}i([x^i]G^k)F^{i-n-1}F(x)=\dfrac{kx^{k-1}}{F^n(x)}=k[x^{-k}]F^{-n}(x)\)
根据引理1: \(n[x^n]G^k(x)=k[x^{-k}]F^{-n}(x)\)

  • 推论(常用):\([x^n]G(x)=\dfrac{1}{n}[x^{-1}]F^{-n}(x)=\dfrac{1}{n}[x^{n-1}](\dfrac{x}{F(x)})^n\)

  • 扩展拉格朗日反演:给定\(H(x)\in F((x)),G(F(x))=x\),则\([x^n]H(G(x))=\dfrac{1}{n}[x^{-1}]\dfrac{H'(x)}{F^n(x)}=\dfrac{1}{n}[x^{n-1}]H'(x)(\dfrac{x}{F(x)})^n\)
    大概意义是复合逆的复合函数。

证明 设$A(x)=H(G(x))$

\(H(x)=H(G(F(x)))=A(F(x))=\sum\limits_{i\ge0}([x^i]A(x))F^i(x)\)

求导可得:\(H'=\sum\limits_{i\ge1}([x^i]A(x))i\cdot F^{i-1}F'\)

同除\(F^n\)得:\(H'F^{-n}=\sum\limits_{i\ge1}([x^i]A(x))i\cdot F^{i-1-n}F'\)

根据引理1:\([x^{-1}]H'F^{-n}=n[x^n]A(x)\)

\(n=0\) 时,分母为 \(0\) 就需要用到下面的另类方法

  • 另类拉格朗日反演:
    \([x^n]G^k(x)=[x^{-k-1}]\dfrac{F'(x)}{F^{n+1}(x)}=[x^{n-k}]F'(x)(\dfrac{x}{F(x)})^{n+1}\)
证明 $G^k(F(x))=x^k$

展开可得:\(\sum\limits_{i}([x^i]G^k)F^i=x^k\)

两侧同除\(x^n\)\(\sum\limits_{i}([x^i]G^k)F'F^{i-n-1}=x^kF'F^{-n-1}\)

根据引理1:\([x^n]G^k=[x^{-1}]x^kF'F^{-n-1}=[x^{-k-1}]F'F^{-n-1}\)

  • 扩展另类拉格朗日反演:\([x^n]H(G(x))=[x^n]H(x)F'(x)(\dfrac{x}{F(x)})^{n+1}\)

应用

【BZOJ3684】大朋友和多叉树

  • 题意:
    给你\(s\)\(m\),在给你\(m\)个数的集合\(D\)。问你叶子数为\(s\)且每个度数大于\(1\)的点的儿子个数在\(D\)中的方案数。
  • 思路:
    \(F(x)\)为叶子数为\(x\)的方案数。
    \(F(x)=x+\sum\limits_{i\in D}F^i(x)\)
    发现\(F(x)\)项比\(x\)项复杂。考虑拉反(代入\(x=F^{(-1)}(x)\))。
    \(x=F^{(-1)}(x)+\sum\limits_{i\in D}x^i\)
    \(F^{(-1)}(x)=x-\sum\limits_{i\in D}x^i\)
    由拉反得:\(Ans=[x^s]F(x)=[x^{s-1}](\dfrac{x}{F^{(-1)}(x)})^s\)
    因此贺一下多项式幂函数+多项式求逆的板子就可以了(板子太烂,心累ing~)。
  • code:
贺的
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
const int N=1e6+5;
const ll mod=950009857;
ll inv[N],inv7,gen[2][N];

ll ksm(ll a,ll b) {ll mul=1;for(;b;b>>=1,a=a*a%mod)if(b&1)mul=mul*a%mod;return mul;}
int rev[N],L,up;
void NTT(ll *a,int op) {
	for(int i=0;i<up;i++) {
		if(rev[i]>i)swap(a[i],a[rev[i]]);
	}
	for(int mid=1;mid<up;mid<<=1) {
		int len=mid<<1;ll w1=gen[op][len];
 		for(int l=0;l<up;l+=len) {
 			ll W=1;
			for(int i=0;i<mid;i++,W=W*w1%mod) {
				int p=l+i,q=p+mid;
				ll x=a[p],y=W*a[q];
				a[p]=(x+y)%mod;a[q]=(x-y)%mod;
			}
		}
	}
}

void gt_up(int len) {
	up=1,L=0;
	while(up<len) {up<<=1,L++;}
	for(int i=1;i<up;i++) {rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));}
}

ll a[N];
void poly_inv(int dep,ll *f,ll *b) {	// b = f mod(x^dep) 
	if(dep==1) {b[0]=ksm(f[0],mod-2);return;}
	poly_inv((dep+1)>>1,f,b);
	gt_up(dep<<1);
	for(int i=0;i<dep;i++)a[i]=f[i];for(int i=dep;i<up;i++)b[i]=a[i]=0;
	NTT(b,0);NTT(a,0);
	for(int i=0;i<up;i++) {a[i]=(2-a[i]*b[i]%mod)*b[i]%mod;}
	NTT(a,1);
	ll i_up=ksm(up,mod-2);
	for(int i=0;i<dep;i++) {b[i]=a[i]*i_up%mod;} for(int i=dep;i<up;i++)b[i]=0;
}

void poly_dao(int n,ll *f,ll *g) {
	for(int i=1;i<n;i++) g[i-1]=f[i]*i%mod;g[n-1]=0;
}
void poly_jf(int n,ll *f,ll *g) {
	for(int i=1;i<n;i++) g[i]=f[i-1]*inv[i]%mod;g[0]=0;
}

ll d[N],g[N];
void poly_ln(int n,ll *f) {
	poly_dao(n,f,d);
	for(int i=0;i<n;i++)g[i]=0;poly_inv(n,f,g);		//****b must be 1,0....0 at first 
	gt_up(n<<1);
	for(int i=n;i<up;i++)g[i]=d[i]=0;
	NTT(d,0),NTT(g,0);
	for(int i=0;i<up;i++)g[i]=d[i]*g[i]%mod;
	NTT(g,1);
	for(int i=0,i_up=ksm(up,mod-2);i<up;i++)g[i]=(i<n)?(g[i]*i_up%mod):0;
	poly_jf(n,g,f);
}
ll c[N];
void poly_exp(int dep,ll *f,ll *b) {
	if(dep==1) {b[0]=1;return;}
	poly_exp((dep+1)>>1,f,b);
	for(int i=0;i<dep;i++)c[i]=b[i];
	poly_ln(dep,c);
	gt_up(dep<<1);
	for(int i=0;i<dep;i++)c[i]=(f[i]-c[i])%mod;for(int i=dep;i<up;i++)b[i]=c[i]=0;
	c[0]++;

	NTT(b,0);NTT(c,0);
	for(int i=0;i<up;i++)b[i]=c[i]*b[i]%mod;
	NTT(b,1);
	for(int i=0,i_up=ksm(up,mod-2);i<up;i++) {
		b[i]=(i<dep)?(b[i]*i_up%mod):0;
	}
}

void poly_pow(int n,ll *f,ll *g,ll k) {
	poly_ln(n,f);
	for(int i=0;i<n;i++) {f[i]=f[i]*k%mod;}
	poly_exp(n,f,g);
}

void gt_gen(int len) {
	inv7=ksm(7,mod-2);
	gt_up(len);
	up=min(up,1<<21);
	gen[0][up]=ksm(7,(mod-1)/up);gen[1][up]=ksm(inv7,(mod-1)/up);
	for(int i=up;i;i>>=1) {
		gen[0][i>>1]=gen[0][i]*gen[0][i]%mod;
		gen[1][i>>1]=gen[1][i]*gen[1][i]%mod;
	}
	inv[1]=1;for(int i=2;i<up;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}

ll f[N],oo[N],ans[N];
int main() {
	int s,m;
	scanf("%d%d",&s,&m);
	for(int i=1;i<=m;i++) {int k;scanf("%d",&k);f[k-1]=-1;}
	f[0]=1;
	gt_gen(s<<1);
	poly_inv(s,f,oo);
	poly_pow(s,oo,ans,s);
	printf("%lld\n",(ans[s-1]*ksm(s,mod-2)%mod+mod)%mod);
	return 0;
}

树的数量

传送门
转载