容斥
容斥原理讲义
从最基本的集合容斥出发,逐步讲到二项式反演、Min-Max 容斥、莫比乌斯反演、子集卷积等竞赛中所有常见形态。
建议课时:3 课时(135 分钟)。前置知识:组合数、快速幂与逆元、基本 DP、位运算。
0. 课前引入:为什么要"容斥"
问题:1 到 100 中,能被 2 或 3 整除的数有多少个?
- 被 2 整除:50 个
- 被 3 整除:33 个
- 直接相加 83?错了,6、12、18…… 被数了两次。
- 被 6 整除:16 个
答案:\(50 + 33 - 16 = 67\)。
"先多算,再减掉多算的部分",这就是容斥。 但当条件有 3 个、10 个、20 个时,"多减了又要加回来"会变得非常复杂。本讲的目标是把这套"加加减减"变成机械化的公式和代码。
1. 基本容斥原理
1.1 公式
设 \(A_1, A_2, \dots, A_n\) 是有限集合,则
展开写:
奇数个集合的交取正,偶数个取负。
1.2 补集形式(更常用)
竞赛中更常见的问法是"一个条件都不满足的方案数":
其中 \(S = \emptyset\) 时交集定义为全集 \(U\)。
讲课提示:这个形式没有"非空"限制、符号是 \((-1)^{|S|}\),比 1.1 更好记,建议学生以这个为主。
1.3 证明(选讲)
对任意元素 \(x\),设它恰好属于 \(k\) 个集合(\(k \ge 1\))。它在右边被计数的次数是:
每个属于并集的元素恰好被数一次。\(\blacksquare\)
这个证明的核心是 \((1-1)^k = 0\),后面所有容斥变体的本质都是它。
1.4 代码:枚举子集
条件个数 \(n \le 20\) 时,直接 \(2^n\) 枚举:
ll ans = 0;
for (int S = 0; S < (1 << n); S++) {
int cnt = __builtin_popcount(S);
ll val = calc(S); // |∩_{i∈S} A_i|,题目具体决定
if (cnt & 1) ans -= val;
else ans += val;
}
1.5 例题:HAOI2008 硬币购物
题意:4 种硬币面值 \(c_1..c_4\),每种有 \(d_i\) 枚,问凑出 \(s\) 元的方案数。多组询问,\(s \le 10^5\)。
分析:
- 若没有枚数限制,是完全背包,\(f[s]\) 可预处理。
- 有限制时,令 \(A_i\) = "第 \(i\) 种硬币用了超过 \(d_i\) 枚"。
- \(|A_i|\):先强制拿 \(d_i+1\) 枚,剩下随便:\(f[s - (d_i+1)c_i]\)。
- 多个集合的交同理,把每个"超限"的硬币先扣掉 \((d_i+1)c_i\)。
每次询问 \(2^4 = 16\) 次查表。
for (int S = 0; S < 16; S++) {
ll rest = s; int cnt = 0;
for (int i = 0; i < 4; i++)
if (S >> i & 1) { rest -= (d[i] + 1) * c[i]; cnt++; }
if (rest < 0) continue;
ans += (cnt & 1 ? -1 : 1) * f[rest];
}
本题体现容斥最典型的用法:"至多 / 恰好"难算,"至少(强制违反)"好算,用容斥转换。
1.6 例题:错排问题
\(n\) 个元素的排列中,没有一个元素在自己原位置的排列数 \(D_n\)。
令 \(A_i\) = "第 \(i\) 个元素在原位"。\(|\bigcap_{i \in S} A_i| = (n - |S|)!\),只与 \(|S|\) 有关。
重要观察:当交集大小只与 \(|S|\) 有关时,\(2^n\) 枚举可以压缩成 \(O(n)\) 求和,乘上 \(\binom{n}{k}\)。这是容斥的第一个优化点。
2. 二项式反演
2.1 从"至少"到"恰好"
许多题目问"恰好 \(k\) 个条件成立"。设
- \(g(k)\):钦定 \(k\) 个条件成立(其余随意)的方案数(好算)
- \(f(k)\):恰好 \(k\) 个条件成立的方案数(要求)
它们的关系是:
(恰好成立 \(i\) 个条件的方案,在钦定 \(k\) 个时会被数 \(\binom{i}{k}\) 次。)
二项式反演给出逆向公式:
2.2 另一种形式
两种形式对应"至少 / 至多"两个方向,记住一种,另一种对称。
2.3 证明思路
把 \(g\) 的定义代入反演式,交换求和顺序,出现 \(\sum_j (-1)^{j} \binom{m}{j}\),由 \((1-1)^m\) 只在 \(m=0\) 时为 1。本质仍是 1.3 的那个恒等式。
2.4 例题:错排的反演视角
\(g(k)\) = 钦定 \(k\) 个在原位 = \(\binom{n}{k}(n-k)!\);\(f(0)\) = 恰好 0 个在原位 = \(D_n\)。
代入反演式即得 1.6 的公式。容斥原理是二项式反演的 \(k=0\) 特例。
2.5 例题:BZOJ 2839 集合计数
题意:\(\{1..n\}\) 的所有 \(2^n\) 个子集中选出若干个(至少一个),使它们的交集恰好有 \(k\) 个元素,求方案数。
分析:
- \(g(i)\):钦定 \(i\) 个元素在交集中。先选这 \(i\) 个:\(\binom{n}{i}\);其余 \(n-i\) 个元素随意,包含这 \(i\) 个元素的子集有 \(2^{n-i}\) 个,从中任选非空子集族:\(2^{2^{n-i}} - 1\)。
- 反演:\(f(k) = \sum_{i=k}^{n} (-1)^{i-k}\binom{i}{k} g(i)\)。
注意 \(2^{2^{n-i}}\) 的指数要对 \(p-1\) 取模(费马小定理)。
2.6 例题:染色问题(恰好用 \(k\) 种颜色)
\(n\) 个位置,\(m\) 种颜色,问恰好用到 \(k\) 种颜色的方案数。
- \(g(i)\) = 钦定用 \(i\) 种颜色(可以有颜色没用上)= \(\binom{m}{i} i^n\)
- 反演得恰好 \(k\) 种:
\(\sum_{i}(-1)^{k-i}\binom{k}{i}i^n = k!\,S(n,k)\),这正是第二类斯特林数的通项公式。
3. 广义容斥:钦定与"贡献系数"
3.1 思想
把容斥看成:对每个"真实状态"\(x\),希望它被计数 \(w(x)\) 次(通常 \(w\) 是 0/1 指示函数)。我们只能计算"钦定状态"\(y\) 的数目 \(g(y)\),其中每个 \(x\) 在 \(g(y)\) 中被数 \(c(y, x)\) 次。找系数 \(\lambda(y)\) 使得
则答案 \(= \sum_y \lambda(y) g(y)\)。
- 基本容斥:\(\lambda(S) = (-1)^{|S|}\)
- 二项式反演:\(\lambda(i) = (-1)^{i-k}\binom{i}{k}\)
- 后面的莫比乌斯反演:\(\lambda(d) = \mu(d)\)
所有容斥都是"选一组系数把多算的抵消掉"。 掌握这个视角后,遇到新形态可以自己列方程解系数。
3.2 例题:NOIP2016 换教室之类的"至少一个"型 DP
很多 DP 题状态里有"是否已经满足了某条件"这一维,\(0/1\) 各记一遍。若条件很多,可以改为钦定哪些条件被违反,用容斥把状态维度去掉。这是容斥优化 DP 状态的常规手段。
4. Min-Max 容斥
4.1 公式
对有限集合 \(S\) 中的实数(或随机变量),
对称地,\(\min(S) = \sum_{T} (-1)^{|T|-1}\max(T)\)。
4.2 证明
不妨设 \(S\) 中元素按大小排序 \(a_1 < a_2 < \dots < a_n\)。考虑 \(a_i\) 作为 \(\min(T)\) 的贡献:\(T\) 必须包含 \(a_i\),且其余元素从 \(a_{i+1}..a_n\) 中选。
只有 \(a_n\) 系数为 1。\(\blacksquare\)
4.3 为什么有用:期望
期望是线性的,所以
许多题目中"所有事件都发生的时刻"(max)难算,"任一事件首次发生的时刻"(min)容易算(几何分布)。
4.4 例题:HAOI2015 按位或
题意:初始 \(x=0\),每秒以概率 \(p_i\) 选中 \(i\)(\(\sum p_i = 1\)),\(x \gets x \mid i\)。求 \(x\) 变成 \(2^n - 1\) 的期望时间。
分析:令 \(t_j\) = 第 \(j\) 位第一次变成 1 的时刻。所求 \(E[\max_j t_j]\)。
对子集 \(T\),\(\min_{j \in T} t_j\) 是"第一次选到与 \(T\) 有交的数"的时刻,服从几何分布:
\(\sum_{i \subseteq \overline T} p_i\) 是子集和,用高维前缀和(FWT)\(O(n 2^n)\) 预处理。
// g[S] = sum_{i ⊆ S} p[i]
for (int j = 0; j < n; j++)
for (int S = 0; S < (1 << n); S++)
if (S >> j & 1) g[S] += g[S ^ (1 << j)];
double ans = 0;
for (int T = 1; T < (1 << n); T++) {
double denom = 1 - g[full ^ T];
if (denom < 1e-10) { puts("INF"); return 0; }
ans += (__builtin_popcount(T) & 1 ? 1 : -1) / denom;
}
4.5 扩展:第 \(k\) 大(kth-Max-Min 容斥)
系数 \(\binom{|T|-1}{k-1}\) 用 3.1 的方法解出。对应题目:PKUSC2018 随机游走、重返现世(后者需要对 \(|T|\) 做 DP 而不是枚举)。
5. 莫比乌斯反演
5.1 莫比乌斯函数
核心性质:
这就是 \((1-1)^k\) 在约数格上的版本:\(n\) 有 \(k\) 个不同质因子,无平方因子约数 \(d\) 对应"选哪些质因子",\(\mu(d) = (-1)^{|\text{选中}|}\)。
线性筛:
mu[1] = 1;
for (int i = 2; i <= N; i++) {
if (!vis[i]) pr.push_back(i), mu[i] = -1;
for (int p : pr) {
if (i * p > N) break;
vis[i * p] = true;
if (i % p == 0) { mu[i * p] = 0; break; }
mu[i * p] = -mu[i];
}
}
5.2 反演公式
第二种(倍数形式)在竞赛中更常用。
5.3 常用变换:\([\gcd = 1]\)
这是把"互质"条件容斥掉的标准手段。
5.4 例题:求 \(\sum_{i=1}^{n}\sum_{j=1}^{m} [\gcd(i,j) = 1]\)
配合整除分块,\(O(\sqrt n)\) 每次询问。
ll solve(int n, int m) {
if (n > m) swap(n, m);
ll ans = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (ll)(smu[r] - smu[l - 1]) * (n / l) * (m / l); // smu 是 mu 前缀和
}
return ans;
}
5.5 例题:求 \(\sum_{i=1}^{n}\sum_{j=1}^{m} \gcd(i,j)\)
方法一:枚举 \(\gcd = d\),转化成 5.4:
令 \(T = dk\):
最后一步用了 \(\varphi = \text{id} * \mu\)(狄利克雷卷积)。
方法二(直接用欧拉函数):\(\gcd(i,j) = \sum_{d \mid \gcd} \varphi(d)\),直接得到同样的式子。
讲课提示:"换元 \(T = dk\),把两层求和合并成一层,内层预处理成积性函数前缀和"是莫反题的通用套路,务必让学生练熟。
5.6 例题:SDOI2015 约数个数和
求 \(\sum_{i=1}^{n}\sum_{j=1}^{m} d(ij)\),\(d\) 为约数个数函数。
关键恒等式:
代入莫反后化为 \(\sum_{d}\mu(d) S(n/d)\,S(m/d)\),其中 \(S(n) = \sum_{i=1}^{n}\lfloor n/i \rfloor\),可整除分块预处理。
5.7 莫反与基本容斥的关系
对"\(1..n\) 中与 \(m\) 互质的数的个数",基本容斥是对 \(m\) 的质因子集合枚举子集;莫反写成 \(\sum_{d \mid m}\mu(d)\lfloor n/d\rfloor\)。两者完全等价,\(\mu\) 自动跳过含平方因子的 \(d\),就是"不选重复质因子"。
6. 子集反演与高维前缀和
6.1 子集和 / 超集和
超集版本同理。这是把莫比乌斯反演从"约数格"搬到"子集格"。
6.2 高维前缀和(SOS DP)
求所有 \(g(S)\) 的 \(O(n 2^n)\) 算法(4.4 中已用过):
// 子集和
for (int j = 0; j < n; j++)
for (int S = 0; S < (1 << n); S++)
if (S >> j & 1) g[S] += g[S ^ (1 << j)];
// 逆变换(子集反演)
for (int j = 0; j < n; j++)
for (int S = 0; S < (1 << n); S++)
if (S >> j & 1) g[S] -= g[S ^ (1 << j)];
逆变换只需把加号改成减号。这正是"一维一维地做差分"。
6.3 例题:CF 449D Jzzhu and Numbers
题意:从数组中选一个非空子序列,使得按位与为 0,求方案数。
分析:令 \(A_j\) = "按位与的第 \(j\) 位为 1"。所求为全部 \(\overline{A_j}\) 的交。
对 \(S\),\(|\bigcap_{j \in S} A_j|\) = 所有元素都包含 \(S\) 的子序列数 = \(2^{\text{cnt}(S)} - 1\),其中 \(\text{cnt}(S)\) = 数组中是 \(S\) 超集的元素个数,用超集和求。
6.4 子集卷积(选讲)
求 \(h(S) = \sum_{T \subseteq S} f(T)\,g(S \setminus T)\)(要求 \(T\) 与 \(S\setminus T\) 不交)。
做法:给每个集合再带一维"元素个数",\(f_k(S) = f(S)[|S| = k]\)。对每个 \(k\) 做子集和变换,然后按 popcount 做多项式乘法,再逆变换取 \(|S| = k\) 的项。复杂度 \(O(n^2 2^n)\)。
7. 容斥优化 DP:钦定与撤销
7.1 思想
有些 DP 直接做需要记录"哪些约束已经满足",状态爆炸。改为:
- 枚举钦定违反哪些约束(或用 DP 隐式枚举),
- 在违反约束的世界里 DP 更容易,
- 按 \((-1)^{\text{违反数}}\) 加权。
当"违反数"很多时,不显式枚举子集,而是在 DP 转移中每违反一次乘 \(-1\)。
7.2 例题:不相邻同色的序列计数
\(n\) 个位置染 \(m\) 色,相邻不能同色。直接做很简单(\(m(m-1)^{n-1}\)),但这里演示容斥写法便于推广:
令 \(A_i\) = "第 \(i\) 与第 \(i+1\) 位同色"。钦定 \(S\) 个相邻对同色,等价于把序列切成 \(n - |S|\) 段,每段同色:\(m^{n - |S|}\)。
推广:如果"同色"改成任意难以直接处理的相邻关系,仍可以这样做,把"段"作为 DP 单位。
7.3 例题:BZOJ 3622 已经没有什么好害怕的了
题意:\(n\) 个 \(a_i\)、\(n\) 个 \(b_j\) 配对,要求 \(a > b\) 的对数恰好比 \(a < b\) 多 \(k\)(转化为恰好 \(t\) 对 \(a > b\))。
分析:
- 排序后 DP:\(f[i][j]\) = 前 \(i\) 个 \(a\) 中钦定 \(j\) 个配到比自己小的 \(b\)(其余暂不配)的方案数。
- \(g(j) = f[n][j] \cdot (n-j)!\)(剩余随意配对)。
- 二项式反演得恰好 \(t\) 对。
"DP 钦定 + 反演"是这类"恰好 k 个"题的标准组合。
7.4 例题:JSOI2015 染色问题(多重约束)
\(n \times m\) 网格,\(c\) 种颜色,要求每行每列至少一个格子有色、每种颜色至少用一次。三重"至少"约束,做三层容斥:
内层 \([(c-k)+1]\) 中的 \(+1\) 是"不染色"。
讲课提示:多重约束的容斥,各维度独立,系数直接相乘。写代码时 \(O(nmc)\) 三层循环,注意先预处理幂。
8. 容斥形态一览
| 形态 | 系数 | 求和范围 | 典型场景 |
|---|---|---|---|
| 基本容斥 | \((-1)^{\lvert S\rvert}\) | 子集 | "都不满足" |
| 二项式反演 | \((-1)^{i-k}\binom{i}{k}\) | \(i \ge k\) | "恰好 k 个" |
| Min-Max 容斥 | \((-1)^{\lvert T\rvert-1}\) | 非空子集 | 期望 max ↔ min |
| kth Min-Max | \((-1)^{\lvert T\rvert-k}\binom{\lvert T\rvert-1}{k-1}\) | 非空子集 | 第 k 大期望 |
| 莫比乌斯反演 | \(\mu(d)\) | 约数 / 倍数 | \(\gcd\) 类求和 |
| 子集反演 | \((-1)^{\lvert S\rvert-\lvert T\rvert}\) | 子集 / 超集 | 位运算计数 |
| 斯特林反演 | \((-1)^{n-k}\begin{bmatrix}n\\k\end{bmatrix}\) 等 | \(k \le n\) | 斯特林数互推(选讲) |
共同本质:找一组系数,使得每个真实对象被恰好数一次(或数 \(w\) 次)。证明工具都是 \((1-1)^k = [k=0]\) 或其变体。
9. 常见错误清单
- 符号搞反。 补集形式是 \((-1)^{|S|}\),并集形式是 \((-1)^{|S|-1}\)。建议只记补集形式。
- "钦定"和"恰好"混淆。 钦定 \(k\) 个成立时其余是"随意",不是"不成立"。
- 空集项漏掉。 补集形式中 \(S = \emptyset\) 对应全集,不能省。
- 模意义下负数。 减法后要
(x % MOD + MOD) % MOD。 - 莫反整除分块边界。 双变量分块
r = min(n/(n/l), m/(m/l)),且要保证 \(l \le \min(n, m)\)。 - Min-Max 容斥要求集合非空,且求期望时要检查概率为 0 导致的 INF。
- 二项式反演的指数模数。 形如 \(2^{2^k}\) 的指数要对 \(p-1\) 取模。
10. 课堂练习
- 1 到 1000 中,不能被 2、3、5 任意一个整除的数有多少个?(答:266)
- 用二项式反演推导 \(D_n\),并验证 \(D_4 = 9\)。
- 求 \(\sum_{i=1}^{n}\sum_{j=1}^{n}\text{lcm}(i,j)\) 的莫反式子(不要求代码)。
- 证明 Min-Max 容斥的 \(\min\) 版本。
- 实现 5.4 的代码,通过洛谷 P2522 [HAOI2011] Problem b(区间版本,四次差分)。
- 思考:4.4 中如果问"\(x\) 恰好变成某个给定值 \(y\)",该怎么做?
11. 推荐题单
| 难度 | 题目 | 考点 |
|---|---|---|
| 入门 | 洛谷 P1450 [HAOI2008] 硬币购物 | 基本容斥 + 背包 |
| 入门 | 洛谷 P3197 [HNOI2008] 越狱 | 补集思想 |
| 基础 | 洛谷 P2522 [HAOI2011] Problem b | 莫反 + 整除分块 |
| 基础 | 洛谷 P3327 [SDOI2015] 约数个数和 | 莫反 + 恒等式 |
| 基础 | 洛谷 P5505 [JSOI2011] 分特产 | 二项式反演 |
| 基础 | CF 449D Jzzhu and Numbers | 子集反演 / SOS DP |
| 提高 | 洛谷 P3175 [HAOI2015] 按位或 | Min-Max 容斥 |
| 提高 | 洛谷 P4859 已经没有什么好害怕的了 | DP 钦定 + 二项式反演 |
| 提高 | 洛谷 P4491 [HAOI2018] 染色 | 二项式反演 + NTT |
| 提高 | 洛谷 P5643 [PKUWC2018] 随机游走 | Min-Max 容斥 + 树上期望 |
| 挑战 | 洛谷 P4707 重返现世 | kth Min-Max 容斥 + DP |
| 挑战 | 洛谷 P6442 [COCI2011-2012#6] KOŠARE | 子集反演进阶 |
附录:一页纸总结
流程:"恰好 / 都不"难算 → 改问"钦定 / 至少" → 选对应的系数 → 求和(子集枚举 / \(\binom{n}{k}\) 压缩 / 整除分块 / SOS DP)→ 处理负数取模。

浙公网安备 33010602011771号