证明基本都是自己瞎证的,如果证法比较丑请见谅。
容斥原理
一道小学题 求 n(n≤109) 以内不能被 2,3,5 整除的整数个数。

考虑这个 Venn 图。三个圆分别表示被 2,3,5 整除的数构成的集合,那么要求的就是圆外的面积。
假设什么限制也不管,只管一共有 n 个数,那么每块都是算一遍。
圆外的面积自然就是总面积减去里面的,我们想到 n−⌊n2⌋−⌊n3⌋−⌊n5⌋。
你发现重合的部分多扣了,所以你又把两两的重合部分加上,现在你的答案是 n−⌊n2⌋−⌊n3⌋−⌊n5⌋+⌊n2×3⌋+⌊n2×5⌋+⌊n3×5⌋。
你发现中间(三圆重合的部分)又多出来了,把它减掉。n−⌊n2⌋−⌊n3⌋−⌊n5⌋+⌊n2×3⌋+⌊n2×5⌋+⌊n3×5⌋−⌊n2×3×5⌋。
你发现它完美了:该算的被算了一遍,别的被算了零遍。
考虑一个比较一般的容斥的式子:
记 A1 到 An 是 n 个集合,U={1,2,⋯,n}。那么
|n⋃i=1Ai|=∑S⊂U,S≠∅(−1)|S|−1|⋂i∈SAi|
为什么这是对的?
考虑一个元素。假设它出现在了 n 个集合中的 k(k>0) 个。则它的贡献恰好是
∑ki=1(−1)i−1(ki)=1−∑ki=0(−1)i(ki)=1−(−1+1)k=1
。我们发现有出现过的算了一次,没出现过的算了零次。
根据上面的经验,我们发现,容斥就是通过加加减减的方式,使得符合要求的方案算到恰好一遍,其他方案算到零遍,以做到不重不漏不多不少。
二项式反演
小学题加强版 对 k=0,1,2,3,分别求出 n(n≤109) 以内恰能被 2,3,5 中的 k 个整除的整数个数。
先考虑 k=3,这时候答案显然是三圆重合的部分,就是 f3=⌊n2×3×5⌋。
然后是 k=2,这时我们想到 ⌊n2×3⌋+⌊n2×5⌋+⌊n3×5⌋。但是你发现中间那块被多算了 3 遍,于是有 f2=⌊n2×3⌋+⌊n2×5⌋+⌊n3×5⌋−(32)f3 了。
接下来算 k=1,和刚才一样,你算出了 f1=⌊n2⌋+⌊n3⌋+⌊n5⌋−(21)f2−(31)f3。
那么 f0=n−(10)f1−(20)f2−(30)f3。
考虑比较一般的问题。你有 n 个限制,对所有的 k,要求出满足恰好 k 个限制的方案数。
对于一个 k,你强行钦定它满足其中 k 个条件,而算出答案为 gk;记最后的答案为 fk。那么根据刚才的经验,很明显:
fk=gk−n∑j=k+1(jk)fj
但这个复杂度是 n2 的,有时候 n 很大,你算不了。有没有更快的做法?
那你移个项,容易得到:gk=∑nj=k(jk)fj。
组合数拆出来:k!gk=∑nj=k1(j−k)!j!fj
设 g′k=gn−k(n−k)!,f′k=fn−k(n−k)!。那么 g′k=∑kj=01(k−j)!f′j。
然后是喜闻乐见的生成函数环节。G1(x)=∑ig′ixi,F1(x)=∑if′ixi。
那么就有 G1(x)=exF1(x)。所以 F1(x)=e−xG1(x)。而 e−x=∑i(−1)ixii!。
这时候我们就有了明显的思路:先从 g 数组转成 G1(x),然后使用 FFT/NTT 做卷积,算出 F1(x),然后转成 f 数组。
时间复杂度 O(nlogn)。
但是有时候我们不仅想这样求,还想把式子给他写得漂亮些。
刚刚我们推到了 F1(x)=e−xG1(x),其中 e−x=∑i(−1)ixii!。
也就是 f′k=∑kj=0(−1)k−j(k−j)!g′j。
k!fk=∑nj=k(−1)j−k(j−k)!j!gj
fk=∑nj=k(jk)(−1)k−jgj。事实上啊,
gk=n∑j=k(jk)fj⇔fk=n∑j=k(jk)(−1)k−jgj
这个式子就是二项式反演了。二项式反演还有更好看的形式:
fn=n∑j=0(−1)j(nj)gj⇔gn=n∑j=0(−1)j(nj)fj
min-max 容斥
再看看这个容斥的式子:
记 A1 到 An 是 n 个集合,U={1,2,⋯,n}。那么|⋃ni=1Ai|=∑S⊂U,S≠∅(−1)|S|−1|⋂i∈SAi|。
试试把 ⋃ 换成 max,把 ⋂ 换成 min,集合 Ai 改成数 ai 吧。那么得到:
nmaxi=1ai=∑S⊂U,S≠∅(−1)|S|−1mini∈Sai
举个例子:
max{2,3,4}=min{2}+min{3}+min{4}−min{2,3}−min{2,4}−min{3,4}+min{2,3,4}=2+3+4−2−2−3+2=4
你发现它竟然是对的!
能证明吗?
一样的思路,不妨假设 a1≤a2≤⋯≤an。考虑 ax 被算到的次数,为:
∑n−xi=0(n−xi)(−1)n−x
(它要是子集的最小值,该子集的其他元素就只能选后面的)。
当 k<n 时,化为 (−1+1)n−k=0;当 k=n 时,化为 1。
故只有最大的那个值贡献到了答案,它就是对的。这就是 min-max 容斥。
但是你觉得这个东西很蠢,最大值明明可以直接算。
之所以要拿出来说,是因为 min-max 容斥在期望下也是对的。
也就是说,
E(nmaxi=1xi)=∑S⊂U,S≠∅(−1)|S|−1E(mini∈Sxi)
成立。
举例说明:袋子里有 n(n≤20) 种颜色的球,每一回合你会拿出一个球然后放回,摸出的球为第 i 种颜色的概率为 pi(∑pi=1)。求期望多少回合后,每种颜色都摸到过至少一次。(HDU4336)
设第 i 种颜色期望 xi 次被第一次摸到,则答案是 E(maxni=1xi)。
你发现 E(maxxi) 不好求,E(mini∈Sxi) 还比较好求,为 1∑i∈Spi。
套用刚刚的式子,就得到
E(maxni=1xi)=∑S⊂U,S≠∅(−1)|S|−1E(mini∈Sxi)=∑S⊂U,S≠∅(−1)|S|−11∑i∈Spi
n 只有 20,直接算就行了。
Wait! 但是我们还没证明 min-max 容斥在期望下也是对的呢!
考虑在这里计算期望的一种方法:
E(maxni=1xi)=∑tP(x=t)maxni=1ti
E(minni=1xi)=∑tP(x=t)minni=1ti
其中 t 是一个长度为 n 的序列。
E(maxni=1xi)=∑tP(x=t)maxni=1ti=∑tP(x=t)∑S⊂U,S≠∅(−1)|S|−1mini∈Sti=∑S⊂U,S≠∅(−1)|S|−1∑tP(x=t)mini∈Sti=∑S⊂U,S≠∅(−1)|S|−1E(mini∈Sxi)
嗯,这样就证完了,也没啥意思。
还有更强的式子
记 U={1,2,⋯,n},kthmaxni=1ai 为 a 数组的第 k 大值,则:
kthmaxni=1ai=∑S⊂U,S≠∅(−1)|S|−k(|S|−1k−1)mini∈Sai
(规定 n<m 时 (nm)=0)
证明:
不妨假设 a1≤a2≤⋯≤an。
∑S⊂U,S≠∅(−1)|S|−k(|S|−1k−1)mini∈Sai=∑ni=1ai∑S⊂U,S≠∅(−1)|S|−k(|S|−1k−1)[ai=minj∈Saj]=∑ni=1ai∑nj=k(n−ij−1)(j−1k−1)(−1)j−k
对于组合数,有等式 (ab)(bc)=(ac)(a−cb−c)。于是:
=∑ni=1ai∑nj=k(n−ik−1)(n−i−k+1j−k)(−1)j−k=∑ni=1ai(n−ik−1)∑nj=k(n−k+1−ij−k)(−1)j−k=∑ni=1ai(n−ik−1)∑n−k+1−ij=0(n−k+1−ij)(−1)j
当 i=n−k+1 时,(n−ik−1)∑n−k+1−ij=0(n−k+1−ij)(−1)j=1;
否则 (n−ik−1)∑n−k+1−ij=0(n−k+1−ij)(−1)j=0。
所以 ∑ni=1ai(n−ik−1)∑n−k+1−ij=0(n−k+1−ij)(−1)j=kthmaxni=1ai
于是证完了。
于是又有
E(kthmaxni=1xi)=∑S⊂U,S≠∅(−1)|S|−k(|S|−1k−1)E(mini∈Sxi)
其实还有一个关于 gcd 和 lcm 的容斥。
它长这样:lcmni=1ai=∏S⊂U,S≠∅(gcdi∈Sai)(−1)|S|−1
其中 U={1,2,⋯,n}。
为什么对?你考虑 ai=∏kpαkk。
- 取两个数的 gcd 就是每个 α 取 min;
- 取两个数的 lcm 就是每个 α 取 max;
- 两个数相乘就是 每个 α 求和;
- 两个数相除就是 每个 α 求差。
于是那个式子就相当于对每个 α 同时搞了个 min-max 容斥,自然就是对的了。
例题
二项式反演
luogu P4859 已经没有什么好害怕的了
luogu P4491 染色
luogu P5401 珍珠
min-max 容斥
HDU 4336 Card Collector
luogu P3175 按位或
HDU4624 Endless Spin
BZOJ 4833 最小公倍佩尔数
luogu P4707 重返现世
AGC 038E Gachapon
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战