关于二项式反演
第一反演公式(定理):
如果多项式 \(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(-1)^{n-i}*(_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;
}