容斥原理-快速上手(Inclusion-Exclusion Principle)详解【含10道例题+代码+公式】

容斥原理-快速上手(Inclusion-Exclusion Principle)详解【含10道例题+代码+公式】

📚 目录


容斥原理用于求解多个集合并集的元素个数,特别是涉及“满足至少一个条件”的问题。


⭐ 二集合公式:

∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ |A \cup B| = |A| + |B| - |A \cap B| AB=A+BAB


⭐ 三集合公式:

∣ 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| ABC=A+B+CABACBC+ABC


⭐ 推广到 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| A1A2An=AiAiAj+AiAjAk+(1)n+1A1A2An


✅ 例题 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| ABC=A+B+CABACBC+ABC
    则:

  • ∣ 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 AB=lcm(2,3)100=6100 → 表示:1~100 中同时被 2 和 3 整除的数的个数,即被 6 整除的个数。

  • ∣ A ∩ C ∣ = ⌊ 100 10 ⌋ |A \cap C| = \left\lfloor \frac{100}{10} \right\rfloor AC=10100→ 表示:1~100 中同时被 2 和 5 整除的数的个数,即被 10 整除的个数。

  • ∣ B ∩ C ∣ = ⌊ 100 15 ⌋ |B \cap C| = \left\lfloor \frac{100}{15} \right\rfloor BC=15100→ 表示:1~100 中同时被 3 和 5 整除的数的个数,即被 15 整除的个数。

  • ∣ A ∩ B ∩ C ∣ = ⌊ 100 30 ⌋ |A \cap B \cap C| = \left\lfloor \frac{100}{30} \right\rfloor ABC=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|) 答案=NAB=N(A+BAB)

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 ABC=2N+3N+5Nlcm(2,3)Nlcm(2,5)Nlcm(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 ABC=21000+31000+5100061000101000151000+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 ABC=500+333+20016610066+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 11000 中,所有能被 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=iABCi=S7+S11+S13Slcm(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=d2k(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 dkN 的最大整数

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 11000 中,所有能被 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 AB=41000+61000lcm(4,6)1000

所以:

答案 = 1000 − ∣ A ∪ B ∣ \text{答案} = 1000 - |A \cup B| 答案=1000AB

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+5N6N10N15N+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| ABC=A+B+CABACBC+ABC

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| 答案=NABC

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=100AB其中 A  3 的倍数, 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 AB=3100+710021100

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| AB=A+BAB

答案是 9999 − ∣ A ∪ B ∣ 9999 - |A \cup B| 9999AB

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)

觉得还可以的话老板赏个赞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值