容斥原理
在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
∣
S
1
⋃
S
2
⋃
S
3
∣
=
∣
S
1
∣
+
∣
S
2
∣
+
∣
S
3
∣
−
∣
S
1
⋂
S
2
∣
−
∣
S
1
⋂
S
3
∣
−
∣
S
2
⋂
S
3
∣
+
∣
S
1
⋂
S
2
⋂
S
3
∣
|S_1\bigcup S_2\bigcup S_3|=|S_1|+|S_2|+|S_3|-|S_1\bigcap S_2|-|S_1 \bigcap S_3|-|S_2 \bigcap S_3|+|S_1 \bigcap S_2\bigcap S_3 |
∣S1⋃S2⋃S3∣=∣S1∣+∣S2∣+∣S3∣−∣S1⋂S2∣−∣S1⋂S3∣−∣S2⋂S3∣+∣S1⋂S2⋂S3∣
n
n
n 个元素以此类推,只要记住奇数个元素是加,偶数个元素是减
证明:假设有
k
k
k 个元素,那么有
C
k
1
−
C
k
2
+
C
k
3
−
C
k
4
+
⋅
⋅
⋅
+
(
−
1
)
k
−
1
C
k
k
=
1
C_{k}^{1}-C_{k}^{2}+C_{k}^{3}-C_{k}^{4}+···+(-1)^{k-1}C_{k}^{k}=1
Ck1−Ck2+Ck3−Ck4+⋅⋅⋅+(−1)k−1Ckk=1
模板题:AcWing 890. 能被整除的数
思路:①:
n
n
n 中
p
p
p 的倍数的个数就是
n
/
p
n/p
n/p
②:要算两个质数的共同拥有的,比如,算
2
2
2 和
3
3
3 的倍数有多少个,就是算
n
n
n 里面
6
6
6 的倍数有多少个。多个质数也是相乘起来就完事了,但注意如果乘积大于了
n
n
n ,那么直接
b
r
e
a
k
break
break 掉就可以了。状压二进制表示选与不选这个质数
AC代码如下:
#include<iostream>
using namespace std;
#define ll long long
int n, m, p[20];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i)
scanf("%d", &p[i]);
int res = 0;
for(int i = 1; i < (1 << m); ++i)
{
int cnt = 0;
ll t = 1;
for(int j = 0; j < m; ++j)
{
if((i >> j) & 1)
{
++cnt;
if(t * p[j] > n)
{
t = -1;
break;
}
t*=p[j];
}
}
if(t != -1)
{
if(cnt & 1)
res += n / t;
else
res -= n / t;
}
}
printf("%d", res);
return 0;
}