二項式反演 ~ Inversion of the Binomial
二項式反演 ~ Inversion of the Binomial
前置知識 容斥原理
眾所周知:
\[\big | \bigcup_{i=1}^n A_i \big |=\sum_i \big|A_i \big|- \sum_{i<j}\big|A_i \cap A_j\big|+\sum_{i<j<k}\big|A_i\cap A_j \cap A_k\big|- \cdots+(-1)^{n-1} \sum_{a_i<a_{i+1}} \big|\bigcap_{i-1}^n A_{a_i}\big| \]
二項式反演
記 \(\complement A\) 為 \(A\)
\[A \cup B=S-\complement A \cap \complement B \]
我們可以對容斥的式子進行變形:
\[\big|\bigcap_{i=1}^n \complement A_i\big|=\big|S\big|-\sum_i \big|A_i \big|+ \sum_{i<j}\big|A_i \cap A_j\big|-\sum_{i<j<k}\big|A_i\cap A_j \cap A_k\big|+ \cdots+(-1)^n \sum_{a_i<a_{i+1}} \big|\bigcap_{i-1}^n A_{a_i}\big| \tag{1} \]
將容斥的式子中 \(A_i\) 替換為 \(\complement A_i\) ,再進行相同的變形:
\[\big|\bigcap_{i=1}^n A_i\big|=\big|S\big|-\sum_i \big|\complement A_i \big|+ \sum_{i<j}\big|\complement A_i \cap \complement A_j\big|-\sum_{i<j<k}\big|\complement A_i\cap \complement A_j \cap \complement A_k\big|+ \cdots+(-1)^n \sum_{a_i<a_{i+1}} \big|\bigcap_{i-1}^n \complement A_{a_i}\big| \tag{2} \]
考慮一種特殊情況:對於任意一個集族 \(\mathcal{U}=\{A_1,A_2,A_3,\cdots,A_n\}\) ,其中任意 \(i\) 個集合的交集都為 \(g(i)\) ,則:
\[g(n)=\big|\bigcap_{a_i<a_{i+1}}^n A_{a_i}\big| \]
並且定義 \(g(0)=|S|\) 。
類似地,令
\[f(n)=\big|\bigcap_{a_i<a_{i+1}}^n \complement A_{a_i}\big| \]
將 \(f,g\) 代入 \((1),(2)\) 兩式中得:
\[f(n)=\sum_{i=0}^n (-1)^i {n \choose i}g(i) \iff g(n)=\sum_{i=0}^n (-1)^i{n \choose i}f(i) \]
二項式反演的不同形式
形式一
\[f(n)=\sum_{i=0}^n (-1)^i {n \choose i}g(i) \iff g(n)=\sum_{i=0}^n (-1)^i{n \choose i}f(i) \]
就是上面那個式子。
形式二
\[f(n)=\sum_{i=0}^n {n \choose i} g(i) \iff g(n)=\sum_{i=0}^n(-1)^{n-i}{n \choose i}f(i) \]
這個形式比較好推。不難發現其中 \(g(i)\) 即為形式一中的 \((-1)^ig(i)\) ,代入即可。
形式三
\[f(n)=\sum_{i=n}^m {i \choose n}g(i) \iff g(n)=\sum_{i=n}^m(-1)^{i-n} {i \choose n} f(i) \]
將右式代入左式可得證。
BZOJ2839 集合計數
題面
一個有 \(N\) 個元素的集合有 \(2^N\) 個不同的子集。選出若干個子集(至少一個),使得其交集的元素個數恰好為 \(K\),求有多少種取法。
題解
設 \(f(k)\) 表示選定 \(k\) 個交集元素的方案數,則有:
\[f(k)={n \choose k}(2^{2^{n-k}}-1) \]
式中 \({n \choose k}\) 表示選定 \(k\) 個元素的方案數。選定 \(k\) 個元素後,還剩下 \(n-k\) 個元素,即有 \(2^{n-k}\) 個集合可以選擇,即有 \(2^{2^{n-k}}-1\) 種選擇集合的方案(至少選一個集合,除去空集)。
設 \(g(i)\) 表示交集元素恰好為 \(i\) 個的方案數。因為選定 \(k\) 個交集元素後,實際的交集元素個數只會大於等於 \(k\) ,則有:
\[f(k)=\sum_{i=k}^n {i \choose k} g(i) \]
這就是一個典型的二項式反演的形式三,可以得到:
\[g(k)=\sum_{i=k}^n (-1)^{i-k} {i \choose k} f(i) =\sum_{i=k}^n (-1)^{i-k} {i \choose k} {n \choose i}(2^{2^{n-i}}-1) \]
於是就可以 \(O(n)\) 求 \(g(k)\) 了。
\(\text{Code:}\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define maxn 1000005
#define R register
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const lxl mod=1e9+7;
inline lxl read()
{
lxl x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
lxl N,K;
lxl inv[maxn],invf[maxn],fac[maxn];
inline void init()// 預處理一下逆元
{
inv[1]=invf[1]=invf[0]=fac[1]=fac[0]=1;
for(lxl i=2;i<=N;++i)
{
inv[i]=(-(mod/i)*inv[mod%i]%mod+mod)%mod;
invf[i]=invf[i-1]*inv[i]%mod;
fac[i]=fac[i-1]*i%mod;
}
}
inline lxl C(int n,int m)
{
return fac[n]*invf[n-m]%mod*invf[m]%mod;
}
int main()
{
// freopen("P2839.in","r",stdin);
N=read(),K=read();
init();
lxl ans=0,tmp=1,type=((N-K)&1)?-1:1;
for(int i=N;i>=K;--i)
{
ans=(ans+type*C(i,K)%mod*C(N,i)%mod*tmp%mod+mod)%mod;
tmp=tmp*(tmp+2)%mod;
type=-type;
}
printf("%lld\n",ans);
return 0;
}