UVA10325 The Lottery [容斥原理]

容斥入门题一道,蒟蒻的第一道自己yy出的容斥

其实就是你统计出n以内能被整除的个数,再用总个数减去可行的个数,就是不可行的个数啦,但是对于231,显然不能枚举,那么就容斥吧。

我们先对于一个数xn以内能被他整除的个数就是n/x向下取整这么多个,所以就可以O(1)的统计出这个个数。但对于多个数字,如果你加上对于xy分别的能被整除的个数的话,那么既能被x整除的又能被y整除的就多算了一次,(可以自己在本子上画维恩图理解),那么就要减去多算的个数,然后依次类推啦。

上代码:

#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;
}
*/
posted @ 2018-06-11 19:21  VictoryCzt  阅读(103)  评论(0编辑  收藏  举报