∣ S 1 ∪ S 2 ∪ S 3 ∣ = ∣ S 1 ∣ + ∣ S 2 ∣ + ∣ S 3 ∣ − ∣ S 1 ∩ S 2 ∣ − ∣ S 1 ∩ S 2 ∣ − ∣ S 1 ∩ S 3 ∣ − ∣ S 2 ∩ S 3 ∣ + ∣ S 1 ∩ S 2 ∩ S 3 ∣ |S_1 ∪ S_2 ∪ S_3| = |S_1|+|S_2|+|S_3|-|S_1∩S_2|-|S_1∩S_2|-|S_1∩S_3|-|S_2∩S_3|+|S_1∩S_2∩S_3| ∣S1∪S2∪S3∣=∣S1∣+∣S2∣+∣S3∣−∣S1∩S2∣−∣S1∩S2∣−∣S1∩S3∣−∣S2∩S3∣+∣S1∩S2∩S3∣
时间复杂度:
O
(
2
n
)
O(2^n)
O(2n)
C
n
1
+
C
n
2
+
C
n
3
+
.
.
.
+
C
n
n
=
2
n
−
C
n
0
=
2
n
−
1
C_n^1+C_n^2+C_n^3+...+C_n^n=2^n-C_n^0=2^n-1
Cn1+Cn2+Cn3+...+Cnn=2n−Cn0=2n−1
能被整除的数
暴力枚举的时间复杂度: O ( n m ) O(nm) O(nm)
容斥原理求解:
- 求 ∣ S i ∣ |S_i| ∣Si∣,即 能被 i 整除的元素个数。
- 问题就转化成了求 ∣ S i ∪ . . . ∪ S j ∣ |S_i∪...∪S_j| ∣Si∪...∪Sj∣,可用容斥原理求解。
- 求 ∣ S p ∣ |S_p| ∣Sp∣ : ⌊ n p ⌋ \lfloor \frac{n}{p} \rfloor ⌊pn⌋
- 时间复杂度: O ( 2 m × m ) O(2^m\times m) O(2m×m)
- 可以用二进制数表示选法
#include <iostream>
using namespace std;
typedef long long LL;
int n, m;
const int N = 18;
int p[N];
LL res;
int main()
{
cin >> n >> m;
for(int i=0; i<m; i++) {
cin >> p[i];
}
// 遍历所有状态
for(int i=1; i<1<<m; i++) {
LL t=1; // 记录乘积
int cnt=0; // 统计1的个数
for(int j=0; j<m; j++) {
if(i>>j & 1) {
t *= p[j];
cnt++;
if(t > n) {
t = -1;
break;
}
}
}
if(t != -1) {
if(cnt%2 == 1) res += n/t;
else res -= n/t;
}
}
cout << res << endl;
return 0;
}