Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
Input
There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
Output
For each case, output the number.
Sample Input
12 2 2 3
Sample Output
7
Solution:
题目中让求能被m集合中任意一个数整除的数的个数(1~n中),算是很裸的一个容斥原理模板题。
我们记num(x1, x2, x3...xn)为能被xi整除的数的个数(x1, x2...xn,为m集合中的数),那么最终的答案就是num(x1) + num(x2) + ... + num(xn) - num(x1, x2) - num(x1, x3) - ...- num(xn - 1, xn) + num(x1, x2, x3) + ... +.........等等,
也就是容斥原理的公式:
我们真正写代码的时候当然不可能把这些一个个写出来,一般都是采用二进制枚举的方式进行计算,注意,奇数个前面是“+”,偶数个是“- ”。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll n, m;
ll a[50];
int main()
{
while(cin >> n >> m)
{
ll x;
int top = 0;
for(int i = 0; i < m; ++ i)
{
cin >> x;
if(x != 0) //因为可能有0的存在,而且0对答案没有影响,也就是任何数都不能和0除。
a[top++] = x;
}
ll ans = 0;
for(int i = 1; i < (1 << top); ++ i)
{
ll cnt = 0, temp;
for(int j = 0; j < top; ++ j)
{
if((1 << j) & i)
{
cnt++;
if(cnt >= 2)
{
temp = temp * a[j] / gcd(temp, a[j]);
}
else
{
temp = a[j];
}
}
}
if(cnt % 2)
{
ans += (n - 1) / temp; //1到n - 1这些数中能被temp整除的个数
}
else
{
ans -= (n - 1) / temp;
}
}
cout << ans << endl;
}
return 0;
}