UVA10325 The Lottery [容斥原理]
容斥入门题一道,蒟蒻的第一道自己yy出的容斥
其实就是你统计出以内能被整除的个数,再用总个数减去可行的个数,就是不可行的个数啦,但是对于,显然不能枚举,那么就容斥吧。
我们先对于一个数,以内能被他整除的个数就是向下取整这么多个,所以就可以的统计出这个个数。但对于多个数字,如果你加上对于和分别的能被整除的个数的话,那么既能被整除的又能被整除的就多算了一次,(可以自己在本子上画维恩图理解),那么就要减去多算的个数,然后依次类推啦。
上代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,a,b;
ll ans,num[20];
ll gcd(ll a,ll b){
if(!b) return a;
else return gcd(b,a%b);
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
void dfs(int pos,ll a,int pd){
ll now=-1ll;
if(!pd) now=1ll;
if(pos)ans+=(n/a)*now;
else a=1;
if(pos==m) return;
for(int i=pos+1;i<=m;i++){
dfs(i,lcm(a,num[i]),pd^1);
}
}
int main(){
while(scanf("%lld%lld",&n,&m)==2){
ans=0;
for(int i=1;i<=m;i++) scanf("%lld",&num[i]);
dfs(0,0,1);
printf("%lld\n",n-ans);
}
return 0;
}
/*
精简版
void slove(int i,int a,long long v)
{
if(a%2)ans+=n/v;else ans-=n/v;
for(;i<=m;i++)
slove(i+1,a+1,lcm(v,num[i]));
}
int main()
{
while(scanf("%lld%d",&n,&m)==2)
{
for(int i=1;i<=m;i++)
scanf("%lld",&num[i]);
for(int i=1;i<=m;i++)
slove(i+1,1,num[i]);
printf("%lld\n",n-ans);ans=0;
}
return 0;
}
*/