原理
S1、S2 、S3 分别代表下图三个圆1、2、3的面积
如果我们想求下面图形构成的面积,该怎么求呢,很简单
S = S1 ∪ S2 ∪ S3=
S1 + S2 + S3
-S1 ∩ S2 - S1 ∩ S3 - S2 ∩ S3
+S1 ∩ S2 ∩ S3
拓展一下,如果是4个圆的面积应该是
S =S1 ∪ S2 ∪ S3 ∪ S 4 =
S1 + S2 + S3 + S4
-S1 ∩ S2 - S1 ∩ S3 - S1 ∩ S4 - S2 ∩ S3 - S2 ∩ S4 - S3 ∩ S4
+S1 ∩ S2 ∩ S3 + S1 ∩ S2 ∩ S4 + S1 ∩ S3 ∩ S4 + S2 ∩ S3 ∩ S4
-S1 ∩ S2 ∩ S3 ∩ S4
可以发现规律 ,S1 ∪ S2 ∪ … ∪ S n = ( ∑ i = 1 n \sum_{i=1}^n ∑i=1nSi) - ( ∑ i , j = 1 n \sum_{i,j=1}^n ∑i,j=1n Si ∩ Sj) + ( ∑ i , j , k = 1 n \sum_{i,j,k=1}^n ∑i,j,k=1n Si ∩ Sj ∩ Sk) -…+ ((-1)n-1 ∑ i , j , k . . . . = 1 n \sum_{i,j,k....=1}^n ∑i,j,k....=1n Si ∩ Sj ∩ Sk ∩…∩ Sn)
上面的是用面积来考虑,如果我们用集合来考虑的话, 若 |S| 代表3个集合并集元素的个数,则:
|S| = |S1 ∪ S2 ∪ S3|=
|S1| + |S2| + |S3|
-|S1 ∩ S2| - |S1 ∩ S3| - |S2 ∩ S3|
+|S1 ∩ S2 ∩ S3|
设 n 个集合并集的元素个数为 |S1 ∪ S2 ∪ … ∪ S n|
那么,|S1 ∪ S2 ∪ … ∪ S n| = ( ∑ i = 1 n \sum_{i=1}^n ∑i=1n|Si|) - ( ∑ i , j = 1 n \sum_{i,j=1}^n ∑i,j=1n| Si ∩ Sj|) + ( ∑ i , j , k = 1 n \sum_{i,j,k=1}^n ∑i,j,k=1n |Si ∩ Sj ∩ Sk|) -…+ ((-1)n-1 ∑ i , j , k . . . . = 1 n \sum_{i,j,k....=1}^n ∑i,j,k....=1n |Si ∩ Sj ∩ Sk ∩…∩ Sn|) ,这就是容斥原理的公式
很容易发现,如果某一项包含奇数个集合时,那么它的符号就是"+",反之,某一项包含偶数个集合时,它的符号就是"-"。
证明
为什么容斥原理是对的呢?
不妨设一个元素 x(x ∈ S1 ∪ S2 ∪ … ∪ S n) 出现在了 k (1≤ k ≤n)个集合中,那么 x 一共会被算C
(
1
k
)
\tbinom{1}{k}
(k1) - C
(
2
k
)
\tbinom{2}{k}
(k2) + C
(
3
k
)
\tbinom{3}{k}
(k3) - C
(
4
k
)
\tbinom{4}{k}
(k4) + … + (-1)k-1C
(
k
k
)
\tbinom{k}{k}
(kk),这个式子是恒等于 1 的(可以证明)。所以,任意 1 个元素 x 只被加了一次,所以说容斥原理是正确的。
上面已经知道计算 3 个集合的并集的元素个数的式子有 7 项,计算4 个集合并集的元素个数的式子有 15 项。
大胆猜测一下,计算 n 个集合的并集的元素个数的式子一共有 2n - 1 项。
证明:
C
(
0
n
)
\tbinom{0}{n}
(n0) + C
(
1
n
)
\tbinom{1}{n}
(n1) + C
(
2
n
)
\tbinom{2}{n}
(n2) + C
(
3
n
)
\tbinom{3}{n}
(n3) + … + C
(
n
n
)
\tbinom{n}{n}
(nn) = 2n
①等式右边代表从 n 个数中选任意多个数的方案数,因为第一个数选或不选有两种方案,第二个数选或不选两种方案,第三个数…第n个数…总共 2n。
②等式左边代表从 n 个数中选 0 个数的方案数 + 从 n 个数中选 1 个数的方案数 + … +从 n 个数中选 n 个数的方案数。
很明显,①②两者的意义是相同的,所以等号成立。
C ( 1 n ) \tbinom{1}{n} (n1) + C ( 2 n ) \tbinom{2}{n} (n2) + C ( 3 n ) \tbinom{3}{n} (n3) + … + C ( n n ) \tbinom{n}{n} (nn) = 2n - 1,得证
例题
样例:
1、2、3、4、5、6、7、8、9、10,质数p={2、3}
2 的倍数的有S2 = {2、4、6、8、10} 5个
3 的倍数的有S3 = {3、6、9} 3个
既是 2 的倍数,也是 3 的倍数的有 S2 ∩ S3 = {6} 1个
所以,5 + 3 - 1 = 7 个
那么,1~n 中 p 的倍数的个数怎么求呢?
答: n/p
既是 pi 的倍数,也是 pj 和 pk 的倍数的个数是 n/pipjpk
思路:
二进制,已知共有 2m - 1 项,每一项所包含的质数都不同,我们可以用 1~2m-1 这 2m - 1 个数,来表示不同的项,每个数都转换成 m 位二进制数后,这 m 位就分别代表着 m 个质数是否包含,1代表包含,0代表不包含
AcWing 890. 能被整除的数
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 20;
int n,m;
int p[N];
int main()
{
cin >> n >> m;
for(int i = 0; i < m; i++) cin >> p[i];
int res = 0;
for(int i = 1; i< 1 << m; i++) // 1~2^m-1这些数代表2^m-1个不同的项
{
int t = 1, cnt = 0; //cnt代表当前枚举的项中包含集合的个数
for(int j=0; j<m; j++)//看这个项的第 j 位是否包含,1代表包含,0代表不包含
if(i >> j & 1) //选
{
if((LL)t * p[j] > n) //此时 n/t = 0,直接break即可
{
t = -1;
break;
}
cnt++;
t *= p[j];
}
if(t != -1)
{
if(cnt % 2) res += n/t; //加奇数项的个数
else res -= n/t; //减偶数项的个数
}
}
cout << res;
}
时间复杂度:O(2^m * m)