容斥原理-快速上手(Inclusion-Exclusion Principle)详解【含10道例题+代码+公式】
📚 目录
- ⭐ 二集合公式
- ⭐ 三集合公式
- ⭐ 推广到 n 个集合时
- ✅ 例题 1:被 2、3 或 5 整除
- ✅ 例题 2:不含 7 且不是 7 的倍数
- ✅ 例题 3:2、3、5 的倍数统计(1000)
- ✅ 例题 4:7、11、13 的倍数和
- ✅ 例题 5:非 4 或 6 的倍数
- ✅ 例题 6:与 2、3、5 互质
- ✅ 例题 7:含数字 3、6、9
- ✅ 例题 8:不是 2、3、7 的倍数
- ✅ 例题 9:能被 3 或 7 整除的概率
- ✅ 例题 10:不含数字 4 和 7
容斥原理用于求解多个集合并集的元素个数,特别是涉及“满足至少一个条件”的问题。
⭐ 二集合公式:
∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ |A \cup B| = |A| + |B| - |A \cap B| ∣A∪B∣=∣A∣+∣B∣−∣A∩B∣
⭐ 三集合公式:
∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ |A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C| ∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣
⭐ 推广到 n 个集合时:
∣ A 1 ∪ A 2 ∪ ⋯ ∪ A n ∣ = ∑ ∣ A i ∣ − ∑ ∣ A i ∩ A j ∣ + ∑ ∣ A i ∩ A j ∩ A k ∣ − ⋯ + ( − 1 ) n + 1 ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A n ∣ |A_1 \cup A_2 \cup \dots \cup A_n| = \sum |A_i| - \sum |A_i \cap A_j| + \sum |A_i \cap A_j \cap A_k| - \cdots + (-1)^{n+1} |A_1 \cap A_2 \cap \dots \cap A_n| ∣A1∪A2∪⋯∪An∣=∑∣Ai∣−∑∣Ai∩Aj∣+∑∣Ai∩Aj∩Ak∣−⋯+(−1)n+1∣A1∩A2∩⋯∩An∣
✅ 例题 1:1~100 中能被 2、3 或 5 整除的数有多少个?
分析:
设:
-
A A A 是能被 2 整除的数
-
B B B 是能被 3 整除的数
-
C C C 是能被 5 整除的数
目标:被 2或3 或 5 整除的数有多少个【后面例题类似】 -
∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ |A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C| ∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣
则: -
∣ A ∣ = ⌊ 100 2 ⌋ |A| = \left\lfloor \frac{100}{2} \right\rfloor ∣A∣=⌊2100⌋
-
∣ B ∣ = ⌊ 100 3 ⌋ |B| = \left\lfloor \frac{100}{3} \right\rfloor ∣B∣=⌊3100⌋
-
∣ C ∣ = ⌊ 100 5 ⌋ |C| = \left\lfloor \frac{100}{5} \right\rfloor ∣C∣=⌊5100⌋
-
∣ A ∩ B ∣ = ⌊ 100 lcm ( 2 , 3 ) ⌋ = ⌊ 100 6 ⌋ |A \cap B| = \left\lfloor \frac{100}{\text{lcm}(2, 3)} \right\rfloor = \left\lfloor \frac{100}{6} \right\rfloor ∣A∩B∣=⌊lcm(2,3)100⌋=⌊6100⌋ → 表示:1~100 中同时被 2 和 3 整除的数的个数,即被 6 整除的个数。
-
∣ A ∩ C ∣ = ⌊ 100 10 ⌋ |A \cap C| = \left\lfloor \frac{100}{10} \right\rfloor ∣A∩C∣=⌊10100⌋→ 表示:1~100 中同时被 2 和 5 整除的数的个数,即被 10 整除的个数。
-
∣ B ∩ C ∣ = ⌊ 100 15 ⌋ |B \cap C| = \left\lfloor \frac{100}{15} \right\rfloor ∣B∩C∣=⌊15100⌋→ 表示:1~100 中同时被 3 和 5 整除的数的个数,即被 15 整除的个数。
-
∣ A ∩ B ∩ C ∣ = ⌊ 100 30 ⌋ |A \cap B \cap C| = \left\lfloor \frac{100}{30} \right\rfloor ∣A∩B∩C∣=⌊30100⌋→ 表示:1~100 中同时被 2、3、5 全部整除的数的个数,即被 30 整除的个数。
from math import gcd
def lcm(a, b):
return a * b // gcd(a, b)
n = 100
a, b, c = 2, 3, 5
count = (n // a) + (n // b) + (n // c) - (n // lcm(a, b)) - (n // lcm(a, c)) - (n // lcm(b, c)) + (n // lcm(a, lcm(b, c)))
print(count)
✅ 例题 2:1~100 中不是 7 的倍数也不含数字 7 的数有多少个?
分析:
- A:包含数字 7
- B:是 7 的倍数
答案 = N − ∣ A ∪ B ∣ = N − ( ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ ) \text{答案} = N - |A \cup B| = N - (|A| + |B| - |A \cap B|) 答案=N−∣A∪B∣=N−(∣A∣+∣B∣−∣A∩B∣)
n = 100
count_A = len([i for i in range(1, n+1) if '7' in str(i)])
count_B = len([i for i in range(1, n+1) if i % 7 == 0])
count_AB = len([i for i in range(1, n+1) if i % 7 == 0 and '7' in str(i)])
res = n - (count_A + count_B - count_AB)
print(res)
✅ 例题 3:1~1000 中是 2、3、5 的倍数的数有多少个?
设定:
设 A A A 为能被 2 整除的数, B B B 为能被 3 整除的数, C C C 为能被 5 整除的数,总数 N = 1000 N = 1000 N=1000,则根据 容斥原理 有:
∣ A ∪ B ∪ C ∣ = ⌊ N 2 ⌋ + ⌊ N 3 ⌋ + ⌊ N 5 ⌋ − ⌊ N lcm ( 2 , 3 ) ⌋ − ⌊ N lcm ( 2 , 5 ) ⌋ − ⌊ N lcm ( 3 , 5 ) ⌋ + ⌊ N lcm ( 2 , 3 , 5 ) ⌋ |A \cup B \cup C| = \left\lfloor \frac{N}{2} \right\rfloor + \left\lfloor \frac{N}{3} \right\rfloor + \left\lfloor \frac{N}{5} \right\rfloor- \left\lfloor \frac{N}{\text{lcm}(2, 3)} \right\rfloor - \left\lfloor \frac{N}{\text{lcm}(2, 5)} \right\rfloor - \left\lfloor \frac{N}{\text{lcm}(3, 5)} \right\rfloor+ \left\lfloor \frac{N}{\text{lcm}(2, 3, 5)} \right\rfloor ∣A∪B∪C∣=⌊2N⌋+⌊3N⌋+⌊5N⌋−⌊lcm(2,3)N⌋−⌊lcm(2,5)N⌋−⌊lcm(3,5)N⌋+⌊lcm(2,3,5)N⌋
代入 $N=1000$,即:
∣ A ∪ B ∪ C ∣ = ⌊ 1000 2 ⌋ + ⌊ 1000 3 ⌋ + ⌊ 1000 5 ⌋ − ⌊ 1000 6 ⌋ − ⌊ 1000 10 ⌋ − ⌊ 1000 15 ⌋ + ⌊ 1000 30 ⌋ |A \cup B \cup C| = \left\lfloor \frac{1000}{2} \right\rfloor + \left\lfloor \frac{1000}{3} \right\rfloor + \left\lfloor \frac{1000}{5} \right\rfloor- \left\lfloor \frac{1000}{6} \right\rfloor - \left\lfloor \frac{1000}{10} \right\rfloor - \left\lfloor \frac{1000}{15} \right\rfloor+ \left\lfloor \frac{1000}{30} \right\rfloor ∣A∪B∪C∣=⌊21000⌋+⌊31000⌋+⌊51000⌋−⌊61000⌋−⌊101000⌋−⌊151000⌋+⌊301000⌋
最终结果为:
∣ A ∪ B ∪ C ∣ = 500 + 333 + 200 − 166 − 100 − 66 + 33 = 734 |A \cup B \cup C| = 500 + 333 + 200 - 166 - 100 - 66 + 33 = 734 ∣A∪B∪C∣=500+333+200−166−100−66+33=734
Python 实现代码:
from math import gcd
def lcm(a, b):
return a * b // gcd(a, b)
n = 1000
a, b, c = 2, 3, 5
res = (n // a + n // b + n // c
- n // lcm(a, b) - n // lcm(a, c) - n // lcm(b, c)
+ n // lcm(a, lcm(b, c)))
print(f"1~{n} 中能被 2、3 或 5 整除的数有:{res} 个")
✅ 例题 4:1~1000 中能被 7、11、13 整除的数的“和”
我们要求:
在 1 ∼ 1000 1\sim1000 1∼1000 中,所有能被 7、11 或 13 整除的数的 和
虽然这是一个 求和问题,但本质仍然使用 容斥原理。只不过:
- 将 “集合元素个数” 换成了 “集合元素的总和”
- 各子集的“和”可以通过 等差数列求和公式 得到。
公式推导:
S = ∑ i ∈ A ∪ B ∪ C i = S 7 + S 11 + S 13 − S lcm ( 7 , 11 ) − S lcm ( 7 , 13 ) − S lcm ( 11 , 13 ) + S lcm ( 7 , 11 , 13 ) S = \sum_{i \in A \cup B \cup C} i = S_7 + S_{11} + S_{13}- S_{\text{lcm}(7,11)} - S_{\text{lcm}(7,13)} - S_{\text{lcm}(11,13)}+ S_{\text{lcm}(7,11,13)} S=i∈A∪B∪C∑i=S7+S11+S13−Slcm(7,11)−Slcm(7,13)−Slcm(11,13)+Slcm(7,11,13)
其中,
- S _ d S\_d S_d 表示:所有能被 d d d 整除的数的和
- k = ⌊ 1000 d ⌋ k = \left\lfloor \dfrac{1000}{d} \right\rfloor k=⌊d1000⌋ 表示:1~1000 中,能被 d d d 整除的最大整数个数
- S _ d = d ⋅ k ( k + 1 ) 2 S\_d = d \cdot \dfrac{k(k+1)}{2} S_d=d⋅2k(k+1) 是从 d d d 开始、以 d d d 为公差的等差数列的求和公式
符号说明:
符号 | 含义说明 |
---|---|
N N N | 总范围上界,本题中为 1000 1000 1000 |
A A A, B B B, C C C | 分别表示能被 7 7 7、 11 11 11、 13 13 13 整除的集合 |
lcm ( a , b ) \text{lcm}(a,b) lcm(a,b) | 最小公倍数(Least Common Multiple) |
⌊ x ⌋ \left\lfloor x \right\rfloor ⌊x⌋ | 向下取整符号 |
k k k | 满足 d ⋅ k ≤ N d \cdot k \leq N d⋅k≤N 的最大整数 |
Python 实现:
def lcm(a, b):
from math import gcd
return a * b // gcd(a, b)
def sum_divisible(n, d):
count = n // d
return d * count * (count + 1) // 2
n = 1000
a, b, c = 7, 11, 13
s1 = sum_divisible(n, a)
s2 = sum_divisible(n, b)
s3 = sum_divisible(n, c)
s12 = sum_divisible(n, lcm(a, b))
s13 = sum_divisible(n, lcm(a, c))
s23 = sum_divisible(n, lcm(b, c))
s123 = sum_divisible(n, lcm(a, lcm(b, c)))
res = s1 + s2 + s3 - s12 - s13 - s23 + s123
print(res)
最终输出结果:
101972
表示:
✅ 在
1
∼
1000
1 \sim 1000
1∼1000 中,所有能被 7、11 或 13 整除的数的和为 101972
✅ 例题 5:1~1000 中既不是 4 也不是 6 的倍数的数有多少个?
设:
- A A A 为能被 4 整除的数
- B B B 为能被 6 整除的数
则:
∣ A ∪ B ∣ = ⌊ 1000 4 ⌋ + ⌊ 1000 6 ⌋ − ⌊ 1000 lcm ( 4 , 6 ) ⌋ |A \cup B| = \left\lfloor \frac{1000}{4} \right\rfloor + \left\lfloor \frac{1000}{6} \right\rfloor - \left\lfloor \frac{1000}{\text{lcm}(4, 6)} \right\rfloor ∣A∪B∣=⌊41000⌋+⌊61000⌋−⌊lcm(4,6)1000⌋
所以:
答案 = 1000 − ∣ A ∪ B ∣ \text{答案} = 1000 - |A \cup B| 答案=1000−∣A∪B∣
from math import gcd
def lcm(a, b):
return a * b // gcd(a, b)
n = 1000
a, b = 4, 6
count = n//a + n//b - n//lcm(a, b)
res = n - count
print(res)
✅ 例题 6:与 2、3、5 互质的数有多少个(<=1000)
分析:
互质表示不含这些因子的数,等价于“不是 2、3、5 的倍数”的数:
设 N = 1000 N=1000 N=1000,则:
答案 = N − ( ⌊ N 2 ⌋ + ⌊ N 3 ⌋ + ⌊ N 5 ⌋ − ⌊ N 6 ⌋ − ⌊ N 10 ⌋ − ⌊ N 15 ⌋ + ⌊ N 30 ⌋ ) \text{答案} = N - \left( \left\lfloor \frac{N}{2} \right\rfloor + \left\lfloor \frac{N}{3} \right\rfloor + \left\lfloor \frac{N}{5} \right\rfloor - \left\lfloor \frac{N}{6} \right\rfloor - \left\lfloor \frac{N}{10} \right\rfloor - \left\lfloor \frac{N}{15} \right\rfloor + \left\lfloor \frac{N}{30} \right\rfloor \right ) 答案=N−(⌊2N⌋+⌊3N⌋+⌊5N⌋−⌊6N⌋−⌊10N⌋−⌊15N⌋+⌊30N⌋)
from math import gcd
def lcm(a, b):
return a * b // gcd(a, b)
n = 1000
a, b, c = 2, 3, 5
bad = (n//a + n//b + n//c
- n//lcm(a,b) - n//lcm(a,c) - n//lcm(b,c)
+ n//lcm(a,lcm(b,c)))
print(n - bad)
✅ 例题 7:1~10000 中含有 3 或 6 或 9 的数个数
分析:
- A A A:包含3
- B B B:包含6
- C C C:包含9
∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ |A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C| ∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣
n = 10000
set_3 = set(i for i in range(1, n+1) if '3' in str(i))
set_6 = set(i for i in range(1, n+1) if '6' in str(i))
set_9 = set(i for i in range(1, n+1) if '9' in str(i))
res = len(set_3 | set_6 | set_9)
print(res)
✅ 例题 8:不是 2、3、7 的倍数的数有多少个?(<=1000)
分析:
设 A A A 是 2 的倍数, B B B 是 3 的倍数, C C C 是 7 的倍数。
答案为:
答案 = N − ∣ A ∪ B ∪ C ∣ \text{答案} = N - |A \cup B \cup C| 答案=N−∣A∪B∪C∣
def lcm(a, b):
from math import gcd
return a * b // gcd(a, b)
n = 1000
a, b, c = 2, 3, 7
count = (n//a + n//b + n//c
- n//lcm(a,b) - n//lcm(a,c) - n//lcm(b,c)
+ n//lcm(a, lcm(b, c)))
print(n - count)
✅ 例题 9:随机选一个 1~100 的整数,能被 3 或 7 整除的概率?
分析:
求的是:
P = ∣ A ∪ B ∣ 100 其中 A 是 3 的倍数,B 是 7 的倍数 P = \frac{|A \cup B|}{100} \quad \text{其中 A 是 3 的倍数,B 是 7 的倍数} P=100∣A∪B∣其中 A 是 3 的倍数,B 是 7 的倍数
∣ A ∪ B ∣ = ⌊ 100 3 ⌋ + ⌊ 100 7 ⌋ − ⌊ 100 21 ⌋ |A \cup B| = \left\lfloor \frac{100}{3} \right\rfloor + \left\lfloor \frac{100}{7} \right\rfloor - \left\lfloor \frac{100}{21} \right\rfloor ∣A∪B∣=⌊3100⌋+⌊7100⌋−⌊21100⌋
def lcm(a, b):
from math import gcd
return a * b // gcd(a, b)
n = 100
a, b = 3, 7
count = n//a + n//b - n//lcm(a, b)
prob = count / n
print(f"概率:{prob:.4f}")
✅ 例题 10:1~9999 中不含数字 4 和 7 的数有多少个?
分析:
可以看成求补集,先计算包含 4 或 7 的数,再用
9999
−
9999 -
9999− 它。
可类比前面的集合容斥做法,
A
A
A 为含 4,
B
B
B 为含 7,则:
∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ |A \cup B| = |A| + |B| - |A \cap B| ∣A∪B∣=∣A∣+∣B∣−∣A∩B∣
答案是 9999 − ∣ A ∪ B ∣ 9999 - |A \cup B| 9999−∣A∪B∣
def is_valid(x):
s = str(x)
return '4' not in s and '7' not in s
count = sum(1 for i in range(1, 10000) if is_valid(i))
print(count)
觉得还可以的话老板赏个赞