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;
}