How many integers can you find
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. 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的集合,集合元素为非负整数。为1…n内能被集合里任意一个数整除的数字个数。n<=2^31,m<=10
分析:
首先我们将能被i整除记为满足性质 Ai A i ,那么根据题意实际是让我们求
|A1⋃A2⋃⋯⋃Am| | A 1 ⋃ A 2 ⋃ ⋯ ⋃ A m |
根据容斥原理的推论:
|A1⋃A2⋃⋯⋃Am| | A 1 ⋃ A 2 ⋃ ⋯ ⋃ A m |
=∑|Ai|−∑|Ai⋃Aj|+∑|Ai⋃Aj⋃Ak|+⋯ = ∑ | A i | − ∑ | A i ⋃ A j | + ∑ | A i ⋃ A j ⋃ A k | + ⋯
+(−1)m+1|A1⋃A2⋃⋯⋃Am| + ( − 1 ) m + 1 | A 1 ⋃ A 2 ⋃ ⋯ ⋃ A m |
根据组合数我们知道它的项数一共有:
C0m+C1m+C2m+⋯+Cmm=2m C m 0 + C m 1 + C m 2 + ⋯ + C m m = 2 m
因为m不超过10,所以完全可以枚举完成
巧妙利用二进制表示取法1代表取0表示不取,然后用按位与得到选取了哪一个
满足奇数个性质是加号,满足偶数个性质是减号
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,a[20];
ll gcd(ll a,ll b){
return b ? gcd(b,a%b) : a;
}
int main(){
while(scanf("%lld%lld",&n,&m) != EOF){
int ans = 0;
vector<int> v;
for(int i = 0; i < m; i++){
scanf("%lld",&a[i]);
if(a[i] > 0) v.push_back(a[i]);//注意不能有0
}
m = v.size();//更新长度
for(int i = 1; i < (1 << m); i++){//注意这里其实枚举到(1<<m)-1即m个1表示m个性质全有
int cnt = 0;
ll x = 1;
for(int t = 0; t < m; t++){//枚举每个性质看当前情况选择了那个性质
if(i & (1 << t)){
cnt++;
x = x * v[t] / gcd(x,v[t]);
}
}
if(cnt & 1) ans += (n - 1) / x;
else ans -= (n - 1) / x;
}
printf("%d\n",ans);
}
return 0;
}