其他分享
首页 > 其他分享> > 关于二项式反演

关于二项式反演

作者:互联网

第一反演公式(定理):

如果多项式 \(f\),\(g\) 有如下关系:

\[\begin{cases} f[n]=\sum_{i=0}^na_{n,i}*g[i]\\ \\ g[n]=\sum_{i=0}^nb_{n,i}*f[i]\\ \end{cases} \]

且 \(a_{i,i}!=0\) ,\(b_{i,i}!=0\) 。

那么对于任意的函数 \(u\),\(v\) 有:

\[u[n]=\sum_{i=0}^na_i*v[i] ⟺ v[n]=\sum_{i=0}^nb_i*u[i] \]

证明:

令:

\[\begin{cases} f=(f_0,f_1,f_2...f_n)^T,g=(g_0,g_1,g_2...g_n)^T\\ \\ u=(u_0,u_1,u_2...u_n)^T,v=(v_0,v_1,v_2...v_n)^T\\ \end{cases} \]

将方程写成矩阵的形式,有:

\[\left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {a_{00}}&{0}&{\cdots}&{0}\\ {a_{10}}&{a_{11}}&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{n0}}&{a_{n1}}&{\cdots}&{a_{nn}}\\ \end{matrix} \right ]* \left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]\]

\[\left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {b_{00}}&{0}&{\cdots}&{0}\\ {b_{10}}&{b_{11}}&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {b_{n0}}&{b_{n1}}&{\cdots}&{b_{nn}}\\ \end{matrix} \right ]* \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]\]

即:

\[\begin{cases} f=A*g \ \ \ (1) \\ \\ g=B*f \ \ \ (2)\\ \end{cases} \]

将 \((2)\) 代入 \((1)\) 中:

\[f=A*B*f \]

\[A*B=I ⇔ A^{-1}=B \]

因此:

\[u=A*v⇔v=A^{-1}*u⇔v=B*u \]


二项式反演:

二项式定理:

\[(a+b)^n=(^n_i) *a^i*b^{n-i} \]

代入公式:

\[\begin{cases} (x-1)^n=\sum_{i=0}^{n}(^n_i) *(-1)^{n-i}*x^i\\ \\ x^n=(1+x-1)^n=\sum_{i=0}^{n}(^n_i) *(x-1)^i\\ \end{cases} \]

因此:

\[g[n]=\sum_{i=0}^{n}(^n_i) *f[i] ⟺ f[n]=\sum_{i=0}^{n}(^n_i) *(-1)^{n-i}*g[i] \ \ \ (1) \]

这就得到了二项式反演的第一种形式

同理,我们可以列出:

\[\begin{cases} (1-x)^n=\sum_{i=0}^{n}(^n_i) *(-1)^i*x^i\\ \\ x^n=\sum_{i=0}^{n}(^n_i) *(x-1)^i=\sum_{i=0}^{n}(^n_i) *(-1)^i*(1-x)^i\\ \end{cases} \]

因此:

\[g[n]=\sum_{i=0}^{n}(-1)^i*(^n_i) *f[i] ⟺ f[n]=\sum_{i=0}^{n}(-1)^i*(^n_i) *g[i] \ \ \ (2) \]

这就得到了二项式反演的第二种形式

第三种形式为:

\[g[k]=\sum_{i=k}^{n}(_k^i)*f[i] ⟺ f[k]=\sum_{i=k}^n(_k^i)*(-1)^{i-k}*g[i] \ \ \ (3) \]

看起来和二项式关系不大,不太好像前面一样,用二项式定理和第一反演公式直接往里带数证明

但我们考虑第一种形式的矩阵写法:

\[\left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(^0_0) }&{0}&{\cdots}&{0}\\ {(^1_0) }&{(^1_1) }&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {(^n_0) }&{(^n_1) }&{\cdots}&{(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]\]

\[ \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{0}&{\cdots}&{0}\\ {(-1)^{1}*(^1_0) }&{(-1)^{1-1}*(^1_1) }&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {(-1)^{n}*(^n_0) }&{(-1)^{n-1}*(^n_1) }&{\cdots}&{(-1)^{n-n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]\]

也就是:

\[\begin{cases} g=A*f \\ f=B*g \\ \end{cases} \]

我们把 \(A\) 和 \(B\) 转置一下:

因为:

\[A*B=I ⇔ A^T*B^T=I \]

所以:

\[\begin{cases} g=A^T*f \\ f=B^T*g \\ \end{cases} \]

也就是:

\[\left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(^0_0) }&{(^1_0) }&{\cdots}&{(^n_0) }\\ {0}&{(^1_1) }&{\cdots}&{(^n_1) }\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {0}&{0}&{\cdots}&{(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]\]

\[\left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{(-1)^{1}*(^1_0) }&{\cdots}&{(-1)^{n}*(^n_0) }\\ {0}&{(-1)^{1-1}*(^1_1) }&{\cdots}&{(-1)^{n-1}*(^n_1) }\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {0}&{0}&{\cdots}&{(-1)^{n-n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right] \]

即:

\[g[k]=\sum_{i=k}^{n}(_k^i)*f[i] ⟺ f[k]=\sum_{i=k}^n(_k^i)*(-1)^{i-k}*g[i] \]

证毕

同理,第四种形式为:

\[g[k]=\sum_{i=k}^{n}(-1)^{i}*(_k^i)*f[i] ⟺ f[k]=\sum_{i=k}^n(-1)^{i}*(_k^i)*g[i] \]

只要将第二种形式写成矩阵形式:

\[\left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{0}&{\cdots}&{0}\\ {(-1)^{0}*(^1_0) }&{(-1)^{1}*(^1_1) }&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {(-1)^{0}*(^n_0) }&{(-1)^{1}*(^n_1) }&{\cdots}&{(-1)^{n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]\]

\[ \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{0}&{\cdots}&{0}\\ {(-1)^{0}*(^1_0) }&{(-1)^{1}*(^1_1) }&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {(-1)^{0}*(^n_0) }&{(-1)^{1}*(^n_1) }&{\cdots}&{(-1)^{n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]\]

转置一下:

\[\left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{(-1)^{0}*(^1_0) }&{\cdots}&{(-1)^{0}*(^n_0) }\\ {0}&{(-1)^{1}*(^1_1) }&{\cdots}&{(-1)^{1}*(^n_1) }\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {0}&{0}&{\cdots}&{(-1)^{n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]\]

\[ \left[ \begin{matrix} {f_{0}}\\ {f_{1}}\\ {\vdots}\\ {f_{n}}\\ \end{matrix} \right]= \left[ \begin{matrix} {(-1)^{0}*(^0_0) }&{(-1)^{0}*(^1_0) }&{\cdots}&{(-1)^{0}*(^n_0) }\\ {0}&{(-1)^{1}*(^1_1) }&{\cdots}&{(-1)^{1}*(^n_1) }\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {0}&{0}&{\cdots}&{(-1)^{n}*(^n_n) }\\ \end{matrix} \right ]* \left[ \begin{matrix} {g_{0}}\\ {g_{1}}\\ {\vdots}\\ {g_{n}}\\ \end{matrix} \right]\]

即:

\[g[k]=\sum_{i=k}^{n}(-1)^{i}*(_k^i)*f[i] ⟺ f[k]=\sum_{i=k}^n(-1)^{i}*(_k^i)*g[i] \ \ \ (4) \]

证毕


错排列问题

一个排列 \(P_{1...n}\),满足 \(P_i≠i\) (每个数都不在自己的位置上)称为错位排列,问这样的排列数。

设 \(dp[i]\) 为长度为 \(i\) 的序列的错排列数

有:

\[n!=\sum_{i=0}^n(_i^n)*dp[i] \]

二项式反演有:

\[dp[n]=\sum_{i=0}^n(_i^n)*i! \]

信封问题

#include<bits/stdc++.h>
using namespace std;
long long n,ans,fac[30];
int main(){
	fac[0]=1;
    for(int i=1;i<=20;i++)fac[i]=fac[i-1]*i;
	scanf("%lld",&n);
	for(int i=0;i<=n;i++){
		long long sum=0;
		sum=fac[n]/fac[i];
		if(i&1)ans-=sum;
		else ans+=sum;
	}
	printf("%lld\n",ans);
    return 0;
}

恰好和至多的转换:

一般来讲,设 \(f[i]\) 为所有元素中,有且仅有 \(i\) 个满足要求的方案数

设 \(g[i]\) 为所有元素中,至少有 \(i\) 个满足要求的方案数

那么 \(f[j]\) 会在 \(g[i]\) 中被统计 \((_i^j)\) 次

\[g[i]=\sum_{i=k}^{n}(_k^i)*f[i] \]

二项式反演有:

\[f[i]=\sum_{i=k}^n(_k^i)*(-1)^{i-k}*g[i] \]

已经没有什么好害怕的了

#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[2005],b[2005],loc[2005];
long long fac[2005],inv[2005];
long long dp[2005][2005],f[2005],g[2005];
const long long md=1e9+9;
inline void init(){
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%md;
	for(int i=2;i<=n;i++)inv[i]=(md-md/i)*inv[md%i]%md;
	for(int i=2;i<=n;i++)inv[i]=inv[i]*inv[i-1]%md;
}
inline long long C(int x,int y){
	return fac[x]*inv[y]%md*inv[x-y]%md;
}
int main(){
	scanf("%d%d",&n,&k);
	init();
	if((n+k)&1){puts("0");return 0;}k=(n+k)>>1;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	for(int i=1,j=0;i<=n;i++){
		while(j<n&&b[j+1]<a[i])j++;
		loc[i]=j;
	}
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=i;j++){
			if(j)dp[i][j]=(dp[i-1][j]+max(0,loc[i]-j+1)*dp[i-1][j-1])%md;
			else dp[i][j]=dp[i-1][j];
		}
	}
	for(int i=1;i<=n;i++)g[i]=dp[n][i]*fac[n-i]%md;
	long long ans=0;
	for(int i=k;i<=n;i++){
		ans=(ans+(((i-k)&1)?-1:1)*g[i]*C(i,k)%md)%md;
	}
	printf("%lld",(ans+md)%md);

	return 0;
}

[NOI Online #2 提高组] 游戏

#include<bits/stdc++.h>
using namespace std;
int n;
long long fac[5005],inv[5005];
const long long md=998244353;
inline void init(){
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%md;
	for(int i=2;i<=n;i++)inv[i]=(md-md/i)*inv[md%i]%md;
	for(int i=2;i<=n;i++)inv[i]=inv[i-1]*inv[i]%md;
}
inline long long C(int x,int y){
	return fac[x]*inv[y]%md*inv[x-y]%md;
}
char c[5005];
int ver[10005],ne[10005],head[5005],cnt;
inline void link(int x,int y){
	ver[++cnt]=y;
	ne[cnt]=head[x];
	head[x]=cnt;
}
int siz[5005],sum[2][5005];
void dfs1(int x,int fi){
	sum[c[x]-'0'][x]++;
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		dfs1(u,x);
		sum[0][x]+=sum[0][u];
		sum[1][x]+=sum[1][u];
	}
}
long long dp[5005][5005],tmp[5005];
void dfs2(int x,int fi){
	siz[x]=1;dp[x][0]=1;
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		dfs2(u,x);
		for(int j=0;j<=siz[x]+siz[u];j++)tmp[j]=0;
		for(int j=0;j<=siz[x];j++){
			for(int t=0;t<=siz[u];t++){
				tmp[j+t]=(tmp[j+t]+dp[x][j]*dp[u][t])%md;
			}
		}siz[x]+=siz[u];
		for(int j=0;j<=siz[x];j++)dp[x][j]=tmp[j];
	}
	if(c[x]=='0')for(int i=siz[x];i;i--)dp[x][i]=(dp[x][i]+dp[x][i-1]*(sum[1][x]-i+1))%md;
	else for(int i=siz[x];i;i--)dp[x][i]=(dp[x][i]+dp[x][i-1]*(sum[0][x]-i+1))%md;
}
long long g[5005],f[5005];
int main(){
	scanf("%d%s",&n,c+1);
	init();
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		link(x,y);link(y,x);
	}
	dfs1(1,1);
	dfs2(1,1);n>>=1;
	for(int i=0;i<=n;i++)g[i]=dp[1][i]*fac[n-i]%md;
	for(int i=0;i<=n;i++){
		for(int j=i;j<=n;j++){
			f[i]=(f[i]+(((j-i)&1)?-1:1)*C(j,i)*g[j])%md;
		}
	}
	for(int i=0;i<=n;i++)printf("%lld\n",(f[i]+md)%md);

	return 0;
}



标签:begin,right,end,matrix,反演,cdots,关于,二项式,vdots
来源: https://www.cnblogs.com/A-Quark/p/15686122.html