题目描述
给出 m(<=20) 个数 a[1],a[2],…,a[m](<=1e9) 求 1~n(<=1e9) 中有多少数不是 a[1],a[2],…,a[m]的倍数。
分析
比较裸的容斥。考虑在1~n中有多少是a[1],...,a[m]的倍数。设是a[i]的倍数的集合为Ai,则=
,然后用容斥原理求
,最后用总个数n减去就是1~n中不是a[1],...,a[m]的倍数的数的个数了。求的过程用Dfs实现,复杂度为
,对于m<=20的数据来说足够了。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
long long n,m,depth;
long long a[25],d,ans;
int flag[25];
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;
}
void dfs(int dep,long long s,int last) {
if (s>n) return;
if (dep==depth+1) {
d+=(n/s);
return;
}
for (int i=last;i<=m;i++) {
if (!flag[i]) {
flag[i]=1;
dfs(dep+1,lcm(s,a[i]),i+1);
flag[i]=0;
}
}
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%lld",&a[i]);
for (int i=1;i<=m;i++) {
memset(flag,0,sizeof(flag));
depth=i;
d=0;
dfs(1,1,1);
if (i&1) ans+=d;
else ans-=d;
}
printf("%lld",n-ans);
return 0;
}