HDU-1796 How many integers can you find
首先说明一下,我没想到用二进制,而是在参考了一位大佬的代码才明白用二进制这道题的容斥定理运用就能方便许多,贴上大佬链接:https://blog.csdn.net/creat2012/article/details/40791385
题目链接:hdu-1796
题意:
有多组输入,第一行为n和m,第二行为m个数字。要求统计小于n的数字中有多少个能被第二行中的m个数字整除。
注意!第二行的输入中可能为零,所以要注意输入时只有大于零的数被允许。
思路:
看到这样要求有多少个数字能被整除的题目,我一般会想到容斥定理。但是第二行中的数字最多能达到十个,此时直接十进制运算运用容斥定理可能很复杂。如果我们利用二进制运算的特点进行求最小公倍数的运算就能方便许多。因为在计算交集时要重复许多步,利用位运算符&就能判断是求几次,例如,3的二进制是11,此时就能求的交集是与之对应的1的1和2的10。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int SIZE = 100;
int arr[SIZE];
long long gcd(long long x, long long y) {
return y == 0 ? x : gcd(y, x%y);
}
long long lcm(long long x, long long y) {
return x/gcd(x, y)*y;
}
int main() {
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
memset(arr, 0, sizeof(arr));
n--;
long long sum = 0;
int shu = 0;
for(int i = 0; i < m; i++) {
int temp;
scanf("%d", &temp);
if(temp > 0) {
arr[shu] = temp;
shu++;
}
}
for(int i = 1; i < (1 << shu); i++) {
int js = 0, tmp = 1;
for(int j = 0; j < shu; j++) {
if(i & (1 << j)) {
js++;
tmp = lcm(tmp, arr[j]);
}
}
if(js%2) {
sum += n/tmp;
} else {
sum -= n/tmp;
}
}
printf("%lld\n", sum);
}
return 0;
}