入门例题
假设班里有 10 个学生喜欢数学,15 个学生喜欢语文,21 个学生喜欢编程,班里至少喜欢一门学科的有多少个学生呢?
是 10+15+21=46 个吗?不是的,因为有些学生可能同时喜欢数学和语文,或者语文和编程,甚至还有可能三者都喜欢。
为了叙述方便,我们把喜欢语文、数学、编程的学生集合分别用 A,B,C 表示,则学生总数等于 ∣A∪B∪C∣。刚才已经讲过,如果把这三个集合的元素个数 ∣A∣,∣B∣,∣C∣ 直接加起来,会有一些元素重复统计了,因此需要扣掉 ∣A∩B∣,∣B∩C∣,∣C∩A∣,但这样一来,又有一小部分多扣了,需要加回来,即 ∣A∩B∩C∣。即
∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣B∩C∣−∣C∩A∣+∣A∩B∩C∣
图示
把上述问题推广到一般情况,就是我们熟知的容斥原理。
设 U 中元素有 n 种不同的属性,而第 i 种属性称为 Pi,拥有属性 Pi 的元素构成集合 Si,那么
i=1⋃nSi=i∑∣Si∣−i<j∑∣Si∩Sj∣+i<j<k∑∣Si∩Sj∩Sk∣−⋯+(−1)m−1ai<ai+1∑i=1⋂mSai+⋯+(−1)n−1∣S1∩⋯∩Sn∣
即
i=1⋃nSi=m=1∑n(−1)m−1ai<ai+1∑i=1⋂mSai
对于每个元素使用二项式定理计算其出现的次数。对于元素 x,假设它出现在 T1,T2,⋯,Tm 的集合中,那么它的出现次数为
Cnt====∣{Ti}∣−∣{Ti∩Tj∣i<j}∣+⋯+(−1)k−1{i=1⋂kTai∣ai<ai+1}+⋯+(−1)m−1∣{T1∩⋯∩Tm}∣(1m)−(2m)+⋯+(−1)m−1(mm)(0m)−i=0∑m(−1)i(im)1−(1−1)m=1
于是每个元素出现的次数为 1,那么合并起来就是并集。证毕。
对于全集 U 下的 集合的并 可以使用容斥原理计算,而集合的交则用全集减去 补集的并集 求得:
i=1⋂nSi=∣U∣−i=1⋃nSi
右边使用容斥即可。
可能接触过容斥的读者都清楚上述内容,而更关心的是容斥的应用。
那么接下来我们给出 3 个层次不同的例题来为大家展示容斥原理的应用。
不定方程非负整数解计数
给出不定方程 ∑i=1nxi=m 和 n 个限制条件 xi≤bi,其中 m,bi∈N. 求方程的非负整数解的个数。
如果没有 xi<bi 的限制,那么不定方程 ∑i=1nxi=m 的非负整数解的数目为 (n−1m+n−1).
略证:插板法。
相当于你有 m 个球要分给 n 个盒子,允许某个盒子是空的。这个问题不能直接用组合数解决。
于是我们再加入 n−1 个球,于是问题就变成了在一个长度为 m+n−1 的球序列中选择 n−1 个球,然后这个 n−1 个球把这个序列隔成了 n 份,恰好可以一一对应放到 n 个盒子中。那么在 m+n−1 个球中选择 n−1 个球的方案数就是 (n−1m+n−1)。
接着我们尝试抽象出容斥原理的模型:
- 全集 U:不定方程 ∑i=1nxi=m 的非负整数解
- 元素:变量 xi.
- 属性:xi 的属性即 xi 满足的条件,即 xi≤bi 的条件
目标:所有变量满足对应属性时集合的大小,即 ∣⋂i=1nSi∣.
这个东西可以用 ∣⋂i=1nSi∣=∣U∣−⋃i=1nSi 求解。∣U∣ 可以用组合数计算,后半部分自然使用容斥原理展开。
那么问题变成,对于一些 Sai 的交集求大小。考虑 Sai 的含义,表示 xai≥bai+1 的解的数目。而交集表示同时满足这些条件。因此这个交集对应的不定方程中,有些变量有 下界限制,而有些则没有限制。
能否消除这些下界限制呢?既然要求的是非负整数解,而有些变量的下界又大于 0,那么我们直接 把这个下界减掉,就可以使得这些变量的下界变成 0,即没有下界啦。因此对于
ai<ai+1⋂1≤i≤kSai
的不定方程形式为
i=1∑nxi=m−i=1∑k(bai+1)
于是这个也可以组合数计算啦。这个长度为 k 的 a 数组相当于在枚举子集。
硬币购物
4 种面值的硬币,第 i 种的面值是 Ci。n 次询问,每次询问给出每种硬币的数量 Di 和一个价格 S,问付款方式。
n≤103,S≤105.
如果用背包做的话复杂度是 O(4nS),无法承受。这道题最明显的特点就是硬币一共只有四种。抽象模型,其实就是让我们求方程 ∑i=14Cixi=S,xi≤Di 的非负整数解的个数。
采用同样的容斥方式,xi 的属性为 xi≤Di. 套用容斥原理的公式,最后我们要求解
i=1∑4Cixi=S−i=1∑kCai(Dai+1)
也就是无限背包问题。这个问题可以预处理,算上询问,总复杂度 O(4S+24n)。
使用容斥原理能够巧妙地求解一些数论问题。
考虑下面的问题:
求最大公约数为 $k$ 的数对个数
设 1≤x,y≤N,f(k) 表示最大公约数为 k 的有序数对 (x,y) 的个数,求 f(1) 到 f(N) 的值。
这道题固然可以用欧拉函数或莫比乌斯反演的方法来做,但是都不如用容斥原理来的简单。
由容斥原理可以得知,先找到所有以 k 为 公约数 的数对,再从中剔除所有以 k 的倍数为 公约数 的数对,余下的数对就是以 k 为 最大公约数 的数对。即 f(k)= 以 k 为 公约数 的数对个数 − 以 k 的倍数为 公约数 的数对个数。
进一步可发现,以 k 的倍数为 公约数 的数对个数等于所有以 k 的倍数为 最大公约数 的数对个数之和。于是,可以写出如下表达式:
f(k)=⌊(N/k)⌋2−i=2∑i∗k≤Nf(i∗k)
由于当 k>N/2 时,我们可以直接算出 f(k)=⌊(N/k)⌋2,因此我们可以倒过来,从 f(N) 算到 f(1) 就可以了。于是,我们使用容斥原理完成了本题。
for (long long k = N; k >= 1; k--) {
f[k] = (N / k) * (N / k);
for (long long i = k + k; i <= N; i += k) f[k] -= f[i];
}
上述方法的时间复杂度为 O(∑i=1NN/i)=O(N∑i=1N1/i)=O(NlogN)。
容斥原理常用于集合的计数问题,而对于两个集合的函数 f(S),g(S),若
f(S)=T⊆S∑g(T)
那么就有
g(S)=T⊆S∑(−1)∣S∣−∣T∣f(T)
接下来我们简单证明一下。我们从等式的右边开始推:
==T⊆S∑(−1)∣S∣−∣T∣f(T)T⊆S∑(−1)∣S∣−∣T∣Q⊆T∑g(Q)Q∑g(Q)Q⊆T⊆S∑(−1)∣S∣−∣T∣
我们发现后半部分的求和与 Q 无关,因此把后半部分的 Q 剔除:
=Q∑g(Q)T⊆(S∖Q)∑(−1)∣S∖Q∣−∣T∣
记关于集合 P 的函数 F(P)=∑T⊆P(−1)∣P∣−∣T∣,并化简这个函数:
F(P)=T⊆P∑(−1)∣P∣−∣T∣=i=0∑∣P∣(i∣P∣)(−1)∣P∣−i=i=0∑∣P∣(i∣P∣)1i(−1)∣P∣−i=(1−1)∣P∣=0∣P∣
因此原来的式子的值是
Q∑g(Q)T⊆(S∖Q)∑(−1)∣S∖Q∣−∣T∣=Q∑g(Q)F(S∖Q)=Q∑g(Q)⋅0∣S∖Q∣
分析发现,仅当 ∣S∖Q∣=0 时有 00=1,这时 Q=S,对答案的贡献就是 g(S),其他时侯 0∣S∖Q∣=0,则对答案无贡献。于是得到
Q∑g(Q)⋅0∣S∖Q∣=g(S)
综上所述,得证。
该形式还有这样一个推论。在全集 U 下,对于函数 f(S),g(S),如果
f(S)=S⊆T∑g(T)
那么
g(S)=S⊆T∑(−1)∣T∣−∣S∣f(T)
这个推论其实就是补集形式,证法类似。