0摘要
本文对二项式反演公式的推导过程以及运用方式作了较为系统的阐释,界定了二项式反演公式中一些较为模糊的概念,提出了不同问题中,二项式反演公式的解决方案。
1浅谈容斥原理
1.1简单容斥
研究二项式反演,先从最基础的容斥开始。引入一个简单的问题:
求100以内,能被3或5或7整除的正整数的个数。
假设能够被3整除的数集为(S_1),能够被5整除的数集为(S_2),能够被7整除的数集为(S_3),那么,能被3或5或7整除的正整数的个数就是(|S_1cup S_2cup S_3|)。
从图中可以看出,想要计算出(|S_1cup S_2cup S_3|),要减去一些重复计算的值。不难得到下面的计算公式:
上述三元公式再推广到(n)元,就是所谓的容斥原理了。
1.2容斥原理
1.2.1容斥原理简单证明
将2.1中提到的问题一般化:设集合(U)中有(n)中不同的属性,第(i)中属性是(P_i),拥有第(i)种属性的元素构成集合(S_i)。那么,
即
证明[1]:考虑(S_i)集合中的任意一个元素(x)被计算了多少次。令(operatorname{count}(x))为(x)被计算的次数,假设(x)出现在集合(T_1,T_2,..,T_m)中,只需要统计这些集合总共被算了多少次即可。显然,(T_i)算了(dbinom{m}{1})次,(T_icap T_j(i<j))算了((-1) imesdbinom{m}{2}),……,(T_1cap T_2cap cdotscap T_m)算了((-1)^{m-1} imesdbinom{m}{m})次。可得:
根据二项式定理,可得:
所以,(S_i)集合中的任意元素都被算了(1)次,容斥原理得证。
1.2.2补集的容斥
设(overline{S_i})表示(S_i)在全集(U)下的补集。根据高一必修一集合的知识,补集的交集与原集的并集有着如下的关系:
反之,补集的并集与原集的交集也有相似的关系:
通过容斥原理可以把若干个集合的并集求出来。而通过上面两条式子,同时求出补集的交集以及原集的并集。这与二项式反演的推导息息相关。如果我们将求若干个数的并集的大小看作一个函数(g),将求若干个数的交集的大小看作一个函数(f),显然可以用容斥原理通过(f)求出(g)。使用补集的容斥,则又可以通过(g)求出(f)。这其实就是二项式反演的容斥解释了。后文将写出详细的推导过程。
2二项式反演公式
2.1反演的概念
演绎推理是我们在数学中经常遇到的一些方法。对于数列来说,通过原数列计算出新的数列叫作演绎,而通过计算出的数列反推出原数列则被称为反演。
如果我们有一个数列,设为(g(x))。假设我们知道了这个数列与另一个数列(f(x))的对应关系。通过这个对应关系,我们不仅能从(f(x))推出(g(x)),还能从(g(x))反推出(f(x))。这个反推的过程,就是所谓的反演了。显然,在反推的过程中,需要求解一个关于(f(x))的方程。
举个例子,假设(g(x))与(f(x))满足:
已知(g(x))求(f(x))。实际上,从(g(x))反推(f(x))只需要解(n)组(n)元一次方程即可。当然,如果仅仅是解线性方程,还不足以给“反演”单独取一个名字。在一些特定的关系式上,反演会化出一些优美的形式。常见的反演有莫比乌斯反演,单位根反演,子集反演,二项式反演等。
2.2从容斥原理到二项式反演
从容斥原理出发,通过一些变换便可以推导出二项式反演公式。
假设全集(U={S_1,S_1,...,S_{n-1},S_n})中任意(i)个元素的并集、交集的大小都相等。设(g(x))是任意(x)个集合的交集,(f(x))是任意(x)个集合的补集的交集。特别地,(g(0)=|U|,f(0)=|U|)。
那么,我们会有以下两条容斥式子:
(|S_1cap S_2cap...cap S_{n-1}cap S_n|=|U|-|overline{S_1}|-|overline{S_2}|-...+(-1)^n imes |overline{S_1}cap overline{S_2}cap...capoverline{S_{n-1}}cap overline{S_n}|=sumlimits_{i=0}^n(-1)^idbinom{n}{i}f(i))
(|overline{S_1}capoverline{ S_2}cap...cap overline{S_{n-1}}cap overline{S_n}|=|U|-|{S_1}|-|{S_2}|-...+(-1)^n imes |{S_1}cap {S_2}cap...cap{S_{n-1}}cap {S_n}|=sumlimits_{i=0}^n(-1)^idbinom{n}{i}g(i))
注意到(g(n)=|S_1cap S_2cap ...cap S_{n-1}cap S_n|\f(n)=|overline{S_1}capoverline{ S_2}cap...cap overline{S_{n-1}}cap overline{S_n}|)
所以,我们就得到了优美的二项式反演:
做一个恒等变换,可以得到更加实用的形式:
2.3二项式反演的代数证明
用(a_i)代替二项式反演的系数,得到一个简化的公式:
在二项式反演中,(a_i=(-1)^idbinom{n}{i})
若(g(n)=sumlimits_{i=0}^na_if(i)Longrightarrow f(n)=sumlimits_{i=0}^nb_ig(i))成立,需要的条件为:
(f(n)=sumlimits_{i=0}^nb_ig(i)=sumlimits_{i=0}^nb_isumlimits_{j=0}^ia_{ij}f(j) = sumlimits_{j=0}^nf(j)sumlimits_{i=j}^nb_ia_{ij})
显然,如果让上式成立,必须满足:
(sumlimits_{i=j}^nb_ia_{ij}=[j=n])
也就是说,现在需要的工作是证明(sumlimits_{i=j}^n(-1)^idbinom{n}{i} imes(-1)^jdbinom{i}{j}=[j=n])
引理:(dbinom{n}{i}dbinom{i}{j}=dbinom{n}{j}dbinom{n-j}{n-i})
引理证明1(代数):
(dbinom{n}{i}dbinom{i}{j}=dfrac{n!}{(n-i)!i!} imes dfrac{i!}{(i-j)!j!}=dfrac{n!}{(n-j)!j!} imesdfrac{(n-j)!}{[(n-j)-(n-i)]!(i-j)!}=dbinom{n}{j}dbinom{n-j}{n-i})
引理证明2(组合意义):
考虑其组合意义:
设数集(|S|=n,|A|=i,|B|=j,Bsube Asube S),求三个集合有多少种不同的情况。
方法一:从(S)中取(i)个数组成集合(A),再从(A)中取出(j)个数组成集合(B)的方案数。显然,方案数为(dbinom{n}{i}dbinom{i}{j})。
方法二:从(S)中取出(j)个数组成集合(B),在从剩下的数中取出(i-j)个数组成集合(A),这样的方案数就是(dbinom{n}{j}dbinom{n-j}{i-j})。
又因为(dbinom{n-j}{n-i}=dbinom{n-j}{i-j}),引理得证。
有了引理,接下来就简单多了:
原式(=sumlimits_{i=j}^n(-1)^{i}(-1)^jdbinom{n}{j}dbinom{n-j}{n-i}=dbinom{n}{j}(-1)^jsumlimits_{i=0}^{n-j}{(-1)}^{i+j}dbinom{n-j}{i}=dbinom{n}{j}(1-1)^{n-j})
当(j ot=n)的时候,原式值为0;当(j=n)时,代入,解得原式值为(1)。
所以,原式(=[j=n])得证。
反之亦然。二项式反演得证。
2.4 小结-二项式反演与广义容斥原理
2.4.1四种常见形式
二项式反演的常见形式主要有以下4种:
形式一:
形式二(较为常用):
形式三:
形式四:(较为常用):
形式一在上文已经提及并证明过了,形式二可以通过形式一恒等变换很轻松地得到。形式一二和形式三四的差别主要在实际意义上,4.2会提到。通过观察不难发现,二项式反演的变换具有十分优美的对称性。文末会附上形式三的证明。
2.4.2广义容斥原理
广义容斥顾名思义是容斥原理的推广与拓展,其核心思想是将解决“至少”类问题转化为解决"恰好"类问题。广义容斥原理的定义是这样的:
设有与性质(1,2,...,n)相关的元素(n)个,(A_i)为满足第(i)种性质的所有元素的集合。假定(|A_i|)表示集合(A_i)的元素个数,定义(P_k)为至少有(k)种性质的元素的元次,则有:
[P_k=sumlimits_{Iin C(n,k)}|(cap_{iin I}A_i)| ]容斥原理利用(P_k)解决了如何求解(|A_1cup A_2cup cdotscup A_n|)和(|overline{A_1} cap overline{A_2}capcdotscapoverline{A_n} |)的问题。
定义(Q_k)为恰好有(k)种性质的元素的元次,即:
[displaystyle Q_k=sumlimits_{Iin C(n,k)}ig|ig(igcaplimits_{iin I}A_iig)capig( igcaplimits_{jin overline I}overline{A_j} ig) ig| ]广义容斥原理则告诉了(P_k)与(Q_k)两者之间的关系如下:
[Q_k=sumlimits_{i=k}^{n}(-1)^{i-k}dbinom{i}{k}P_{i} ]
可以用二项式反演公式证明/理解广义容斥原理。
引理:恰好有(i)种性质的元素的元次(即 (Q_k))在(P_k(kleq i))中被计算了(dbinom{i}{k})次。
引理证明:考虑任意恰好满足(m(kleq m))种性质的元素(x),假设(x)属于集合(S_1,S_2,...,S_m),定义(operatorname{count}(x))表示(x)被计算的次数。根据:
可得:
所以,任意(x)满足恰好(m)种性质的元次在(P_k)种被计算了(dbinom{m}k)次。引理得证。
所以,对于每个(Q_i(kleq i)),都在(P_k)中计算了(dbinom{i}{k})次。即
根据二项式反演公式(形式四)可得
广义容斥原理成立。以上就是从二项式反演的角度解释广义容斥原理。可见,反演的形式一二对应着容斥原理,形式三四则对应了广义容斥原理。
3二项式反演公式计数
3.1几个经典问题
3.1.1全错位排列问题
这是十分经典的问题,可以从二项式反演的角度思考。
定义(g(x))表示(x)个数中,至多有(x)个(a_i ot=i)的总方案数。(f(x))表示(x)个数的全错位排列的方案数。显然,(g)和(f)满足如下关系
(g(x))又满足如下关系式:
可以通过二项式反演得到(f(n)):
(f(n)=sumlimits_{i=0}^n(-1)^{n-i}dbinom{n}{i}g(i) \=sumlimits_{i=0}^n(-1)^{n-i}dbinom{n}{i}i!\ =sumlimits_{i=0}^n(-1)^{n-i}dfrac{n!}{(n-i)!}\=n!sumlimits_{i=0}^ndfrac{(-1)^i}{i!})
这就是所谓的全错位排列公式:
3.1.2第二类斯特林数
(n)个不同的球放入(m)个不同的盒子,要求每个盒子非空,共有几种方案?
本题的限制是“每个盒子非空”。因此,定义(g_n(m))表示(n)个不同的球放入(m)个不同的盒子,至多有(m)个盒子非空的方案数。定义(f_n(m))表示(n)个不同的球放入(m)个不同的盒子,恰好有(m)个盒子非空的方案数。
可以通过排列组合直接算出(g_n(m)):
(f_n)与(g_n)的关系也可以算出:
二项式反演得:
所以,
第二类斯特林数:(n)个不同的球放入(m)个相同的盒子,要求每个盒子非空,共有几种方案?
直接将上面的答案除以(m!)即可。
3.1.3染色问题
给定从左到右(n)个球,将这(n)个球用(k)种颜色染色。要求相邻两个球必须是不同的颜色,并且每种颜色恰好用一次,问有多少种染色方案。
定义(g_n(x))表示(n)个球,至多用(x)种颜色染色的总方案数。(f_n(x))表示(n)个球,恰好用(x)种颜色染色的方案数(钦定(x)种颜色)。关系式如下:
(g_n(k))又容易直接算出:
二项式反演得到:
(f_n(k)=sumlimits_{i=0}^{k}(-1)^{k-i}dbinom{k}{i}g_n(i)\=sumlimits_{i=0}^k(-1)^{k-i}dbinom{k}{i}i(i-1)^{n-1})
最后的结果:
3.1.4 动态规划计数问题
题意简述:给出(n)个(a_i),以及(n)个(b_i),要求两两配对使得(a>b)得对数减去(a<b)的对数等于(k)。
(0leq kleq nleq 2000),保证(a,b)无相同元素。
题解:
假设(a>b)的对数为(x),那么有:(n-2x=k)。所以,(x=dfrac{n-k}{2})
考虑如何计算恰好有(x)对(a>b)。可以从二项式反演的角度入手,先计算至少有(x)对(a>b)的方案数。
可以将(a,b)从小到大排序。设(F(i,j))表示前(i)个(a_i)中,恰好有(j)对(a>b)的方案数。定义(r(i))表示比(a_i)小的最后一个(b)的位置。可以列出状态转移方程:
定义(g(x))表示至少有(x)对(a>b)的方案数(有重复),(f(x))表示恰好有(x)对(a>b)的方案数。可以通过状态转移方程求得(g(x)):
显然,(f(i))在(g(x))中被重复计算了(dbinom{i}{x})次。可以列出(g(x))与(f(i))的关系式:
通过二项式反演,可得:
(f(x))即为所求。
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005;
const long long mod = 1e9 + 9;
inline int read(){
int w = 0, f = 1; char ch = getchar();
while(ch < '0' or ch > '9') {if(ch == '-') f = -f; ch = getchar();}
while(ch >= '0' and ch <= '9') w = w*10 + ch - '0', ch = getchar();
return w*f;
}
long long f[maxn][maxn], Fac[maxn], g[maxn], FacInverse[maxn];
long long quickpow(long long x, long long y){
long long cnt = 1ll, basic = x;
while(y){
if(y&1) cnt = cnt*basic%mod;
basic = basic*basic%mod, y >>= 1;
}
return cnt;
}
long long C(long long x, long long y){
return Fac[x]*FacInverse[x - y]%mod*FacInverse[y]%mod;
}
int N, K, a[maxn], b[maxn], r[maxn];
int main(){
N = read(), K = read();
for(int i=1; i<=N; i++) a[i] = read();
for(int i=1; i<=N; i++) b[i] = read();
sort(a+1, a+N+1); sort(b+1, b+N+1);
for(int i=1; i<=N; i++) r[i] = upper_bound(b+1, b+N+1, a[i]) - b - 1;
f[0][0] = 1ll;
for(int i=1; i<=N; i++){
f[i][0] = f[i-1][0];
for(int j=1; j<=i; j++){
f[i][j] = f[i-1][j];
if(r[i] - j + 1 >= 0) f[i][j] = (f[i][j] + f[i-1][j-1]*(r[i] - j + 1ll))%mod;
}
}
Fac[0] = 1ll;
for(int i=1; i<=N; i++) Fac[i] = (Fac[i-1]*(long long)i)%mod;
FacInverse[N] = quickpow(Fac[N], mod - 2ll);
for(int i=N-1; i>=0; i--) FacInverse[i] = (FacInverse[i+1]*(long long)(i + 1ll))%mod;
for(int i=0; i<=N; i++) g[i] = f[N][i]*Fac[N-i]%mod;
long long ans = 0ll; K = (N + K)/2;
for(int i=K; i<=N; i++){
long long tmp = (i-K)%2?-1:1;
ans = (ans + tmp*C(i, K)*g[i]%mod)%mod;
}
printf("%lld", (ans%mod + mod)%mod);
return 0;
}
3.2归纳-计数问题的转换
3.2.3至多至少概念的界定
在一般的问题中,至多至少对应的是未知的答案。也就是说,当问题的答案不确定时,才会有“至多”“至少”的概念,以限制答案所在的范围。然而当答案已经确定了之后,至多至少的概念也就显得多余了,因为答案已经确定,不需要再用至多至少去限制了。
但是,使用二项式反演解决问题的过程中,往往会碰到这样的情况:有若干个性质,(g(i))的意义是已经钦定了有(i)个性质,剩下性质的不作限制。这时候,往往会用“至少(i)个性质”来描述(g(i))。这是不准确的。但出于习惯,本文依然使用了“至多”或“至少”以描述(g(i))。据此,提出计数问题中“至多”“至少”概念的界定:
- 至少:钦定了(i)个性质,剩下的性质不作限制。
- 至多:钦定了(i)个性质不作限制,剩下的必须满足性质。
3.2.2至多与恰好的转换
解决上文4.1的问题的过程,其实就用到了“至多”转“恰好”的思想。本质上是将所有小于等于一个数值的“恰好”累加。这样就会得到一个连接至多与恰好的式子。假设(g(x))表示从有若干个元素的集合中,选出若干个至多有(x)种不同性质的元素的集合总方案数,(f(x))表示从有若干个元素的集合中,选出若干个恰好有(x)种不同性质的元素的集合方案数,假设共有(n)种不同的性质。那么,根据上面的分析,容易列出下面的式子:
如果通过上述方式求出了(g(x)),那么就可以通过反演轻松求出(f(i)):
当然,直接使用容斥原理也可以得到相同的结论。
这样一来,解决“至多”类问题就相当于解决了“恰好”类问题。"至多"类问题转“恰好”类问题考虑形式一、二。
3.2.3至少与恰好的转换
与4.3.1相似将(g(x))定义中的“至多”改为“至少”,就可以用形式四直接列出式子:
同样的,给出反演后的结果:
使用广义容斥原理可以得到同样的结果。
解决“至少”类问题也相当于解决了“恰好”类问题。“至少”类问题转“恰好”类问题考虑形式二、三。在遇到“恰好”类问题时,不妨先思考一下"至少"或“至多”的形式,或许可以用反演直接解决问题。
4多元二项式反演公式
4.1二项式反演公式:从一元到多元
在一些计数类题目中,涉及到了高维的计数,需要用到高维的容斥原理。这时候,一元的二项式反演公式就不够用了,要推广到多元的形式。给出多元二项式反演公式[2]:设对任意(m)个非负整数(n_1,n_2,...,n_m),(f(n_1,n_2,cdots,n_m))及(g(n_1,n_2,cdots,n_m))都是整数,且:
那么,
注:公式中(sumlimits_{k_i=0}^{n_i}=egin{matrix}underbrace{sumlimits_{k_1=0}^{n_1}cdots sumlimits_{k_i=0}^{n_i}cdotssumlimits_{k_m=0}^{n_m}}\共m个end{matrix})
证明:
(displaystyle sum_{k_i=0}^{n_i}prod_{i=1}^m(-1)^{n_i-k_i}dbinom{n_i}{k_i}g(k_1,k_2,cdots,k_m)\displaystyle=sum_{k_i=0}^{n_i}prod_{i=1}^m(-1)^{n_i-k_i}dbinom{n_i}{k_i}sumlimits_{t_i=0}^{k_i}prod^m_{i=1}dbinom{k_i}{t_i}f(t_1,t_2,cdots,t_m)\displaystyle =sum_{t_i=0}^{n_i} sum_{k_i=t_i}^{n_i}prod_{i=1}^m(-1)^{n_i-k_i}dbinom{n_i}{k_i}dbinom{k_i}{t_i} f(t_1,t_2,cdots,t_m))
引理:(displaystyle sum_{i=j}^n(-1)^{n-i}dbinom{n}{i}dbinom{i}{j}=[j=n])
证明:原式(=displaystyle sum_{i=0}^{n-j}(-1)^{n-i-j}dbinom{n}{i+j}dbinom{i+j}{j}=dbinom{n}{j}sum_{i=0}^{n-j}(-1)^{n-i-j}dbinom{n-j}{n-i-j}=dbinom{n}{j}(1-1)^{n-j})
当(n ot= j)时,原式(=0)
当(n=j)时,原式(=(-1)^{0}dbinom{n}{n}dbinom{n}{n}=1)
综上,原式(=[j=n])
根据引理可得,原式(=g(n_1,n_2,cdots ,n_m))
多元二项式反演得证。
4.2高维计数问题实例
4.2.1CF997C Sky Full of Stars
题意简述:有一个(n imes n(nleq 10^6))的正方形网格,用红色,绿色,蓝色三种颜色染色,求有多少种染色方案使得至少一行或一列是同一种颜色。
题解:
设(g(x,y))表示钦定(x)行(y)列染成同种颜色,其它随意的方案数。(f(x,y))表示恰好有(x)行,(y)列染成同一种颜色的方案数。那么,有:
根据多元二项式反演公式可得:
考虑如何算出(g(x,y))。分类讨论:
- (x ot=0)且(y ot= 0),(g(x,y)=dbinom{n}{x}dbinom{n}{y}3^{(n-x)(n-y)+1})
- (x=0)或(y=0),(g(x,0)=dbinom{n}{x}3^{x+n(n-x)})
- (x=y=0),(g(0,0)=3^{n^2})
由于题目求得是“至少一行或一列是同一种颜色”,所以我们只需要用总方案数减去(f(0,0))即可。
再次分类讨论:
-
(x ot=0)且(y ot=0),设(ans_1)表示这部分的答案。则,
(displaystyle ans_1=sum_{i=1}^nsum_{j=1}^n(-1)^{i+j}inom{n}{i}inom{n}{j}3^{(n-i)(n-j)+1}\displaystyle= 3^{n^2+1}sum_{i=1}^n(-1)^iinom n i3^{-ni}sum_{j=1}^n(-1)^jinom{n}{j}3^{ij-nj}\displaystyle =3^{n^2+1}sum_{i=1}^n(-1)^iinom{n}{i}3^{-ni}sum_{j=1}^ninom{n}{j}(-3^{i-n})^j)
根据二项式定理可得:
(displaystyle ans_1=3^{n^2+1}sum_{i=1}^n(-1)^iinom{n}{i}3^{-ni}((1-3^{i-n})^j-1))
-
(x=0)或(y=0),设(ans_2)表示这部分的答案。容易发现,无论是(x=0)还是(y=0),结果都一样。所以,
(displaystyle ans_2=2sum_{i=1}^n(-1)^iinom{n}{i}3^{i+n(n-i)}\displaystyle =2 imes 3^{n^2}sum_{i=1}^n(-1)^i3^{(1-n)^i}inom{n}{i}\displaystyle =2 imes3^{n^2}((1-3^{1-n})^i-1))
-
(x=y=0),设(ans_3)表示这部分的答案,则
(ans_3=3^{n^2})
综上,最终的结果为(3^{n^2}-(ans_1+ans_2+ans_3)=-(ans_1+ans_2))
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
const long long mod = 998244353ll;
long long quickpow(long long x, long long y){
y = (y%(mod - 1ll) + mod - 1ll)%(mod - 1ll);
x = (x%mod + mod)%mod;
long long cnt = 1ll, basic = x;
while(y){
if(y&1) cnt = cnt*basic%mod;
basic = basic*basic%mod, y >>= 1;
}
return cnt;
}
int N; long long Fac[maxn], FacInverse[maxn];
long long C(long long x, long long y){
return Fac[x]*FacInverse[x-y]%mod*FacInverse[y]%mod;
}
int main(){
scanf("%d", &N);
Fac[0] = 1ll;
for(int i=1; i<=N; i++) Fac[i] = Fac[i-1]*(long long)i%mod;
FacInverse[N] = quickpow(Fac[N], mod - 2ll);
for(int i=N; i>=1; i--) FacInverse[i-1] = FacInverse[i]*(long long)i%mod;
long long ans = 0ll, opt = 1ll;
for(int i=1; i<=N; i++){
opt *= -1ll;
ans += opt*quickpow(3ll, -(long long)N*i)*C(N,i)%mod*(quickpow(1ll - quickpow(3ll, i-N), N) - 1ll)%mod, ans %= mod;
}
ans = (ans*quickpow(3ll, (long long)N*N+1ll))%mod;
ans=(ans+2ll*quickpow(3ll, 1ll*N*N)%mod*(quickpow(1ll-quickpow(3ll , 1ll - N), N)-1))%mod;
printf("%lld", (mod - ans)%mod);
return 0;
}
5总结
二项式反演公式的本质是容斥原理,在解决一些计数问题的过程中,二项式反演公式对简化问题有着重要的作用。