题目地址:
https://www.acwing.com/problem/content/892/
给定一个整数 n n n和 m m m个不同的素数 p 1 , . . . , p m p_1,...,p_m p1,...,pm,求 1 ∼ n 1\sim n 1∼n中能被 p 1 , . . . , p m p_1,...,p_m p1,...,pm之一整除的整数有多少个。
输入格式:
第一行包含整数
n
n
n和
m
m
m。第二行包含
m
m
m个质数。
输出格式:
输出一个整数,表示满足条件的整数的个数。
数据范围:
1
≤
m
≤
16
1\le m\le 16
1≤m≤16
1
≤
n
,
p
i
≤
1
0
9
1\le n,p_i\le 10^9
1≤n,pi≤109
可以用容斥原理。设 S i = { 1 ≤ k ≤ n : p i ∣ n } S_i=\{1\le k\le n:p_i|n\} Si={1≤k≤n:pi∣n},由容斥原理知道,答案是: ∑ i = 1 m ∣ S i ∣ − ∑ i 1 < i 2 ∣ S i 1 ∩ S i 2 ∣ + ∑ i 1 < i 2 < i 3 ∣ S i 1 ∩ S i 2 ∩ S i 3 ∣ − . . . + ( − 1 ) m − 1 ∣ S 1 ∩ S 2 ∩ . . . ∩ S m ∣ \sum_{i=1}^{m} |S_i|-\sum_{i_1<i_2} |S_{i_1}\cap S_{i _2}|+\sum_{i_1<i_2<i_3} |S_{i_1}\cap S_{i _2}\cap S_{i_3}|-...+(-1)^{m-1} |S_1\cap S_2\cap...\cap S_m| i=1∑m∣Si∣−i1<i2∑∣Si1∩Si2∣+i1<i2<i3∑∣Si1∩Si2∩Si3∣−...+(−1)m−1∣S1∩S2∩...∩Sm∣我们只需算出每个 1 ∼ n 1\sim n 1∼n中被 p i p_i pi整除的数的个数,这个个数就是 ⌊ n p i ⌋ \lfloor \frac{n}{p_i}\rfloor ⌊pin⌋。因为 m ≤ 16 m\le 16 m≤16,可以用二进制枚举的方式来枚举所有取哪些素数的情况,即某个数 x x x的右起第 i i i个二进制位(这里从 1 1 1开始计数)是 1 1 1就表示第 p i p_i pi是取的。代码如下:
#include <iostream>
using namespace std;
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++) {
// prod存当前取法的素数乘积,cnt存当前取法的素数个数
int prod = 1, cnt = 0;
// 看一下第j + 1个素数是否取了
for (int j = 0; j < m; j++)
if (i >> j & 1) {
cnt++;
// 如果当前取法的素数乘积大于n了,那这个乘积无法作为因子,直接退出循环
if ((long) prod * p[j] > n) {
prod = -1;
break;
}
prod *= p[j];
}
if (prod != -1)
if (cnt % 2) res += n / prod;
else res -= n / prod;
}
cout << res << endl;
}
时间复杂度 O ( 2 m m ) O(2^mm) O(2mm),空间 O ( 1 ) O(1) O(1)。