关于二项式反演
作者:互联网
第一反演公式(定理):
如果多项式 \(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