Problem Description
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
题意:给出整数N和数集M={a1,a2,a3...am},要求区间【1,N】中能被M中任意一个数ai整除的个数。
解题思路:用到了容斥原理(参见大佬的博客)http://www.cppblog.com/vici/archive/2011/09/05/155103.html#userconsent%23
百度百科:在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
这道题目就是让M中的数组合,求出每种组合的最小公倍数,按照组合中数的个数把结果奇加偶减。
code:
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
int st[12];
LL n;
LL gcd(LL a, LL b)
{
if (b == 0)
return a;
return gcd(b, a%b);
}
LL lcm(LL a, LL b)
{
return a / gcd(a,b)*b;
}
int fid(int num)//寻找组合
{
int cnt=0, c=0;
LL Lcm = 1;
while (num)
{
if (num & 1) { Lcm = lcm(Lcm, (LL)st[cnt]);c++; }
cnt++;
num /= 2;
}
LL ans = (n - 1) / Lcm;
if (c % 2) return ans;
return -ans;
}
void solve(int m)//枚举各个状态二进制优化
{
LL sum = 0;
for (int i = 1;i < (1 << m);i++)
{
sum += fid(i);
}
cout << sum << endl;
}
int main()
{
int m;
while (cin >> n >> m)
{
int cnt = 0;
for (int i = 0;i < m;i++)
{
int k;
cin >> k;
if (k) st[cnt++] = k;
}
solve(cnt);
}
return 0;
}