容斥原理(枚举二进制)-HDU1796(重)

来源:互联网 发布:php高级工程师 面试 编辑:程序博客网 时间:2024/06/05 11:41

https://vjudge.net/problem/HDU-1796

将符合条件的m个数,看作m位,每位是0或者是1,那么一共有2^m种状态,只要判断一下每一个状态有多少个1,也就是有多少个数(重叠多少次),记为k,每一个1代表哪几个具体的数,求这几个数的最小公倍数,然后(n-1)/lcm, 利用k的值来判断应该减去还是加上。

参考:http://blog.csdn.net/sr_19930829/article/details/44938217

#include <iostream>#include <cstdio>using namespace std;typedef long long ll;const int inf=0x3f3f3f3f;const int maxn=25;ll num[maxn];//存有效数字int cnt;ll ans;ll n,m;ll gcd(ll a,ll b){    return b==0?a:gcd(b,a%b);}ll LCM(ll a,ll b){    return a*b/gcd(a,b);}int main(){    while(scanf("%I64d%I64d",&n,&m)!=EOF)    {        cnt=0;        ans=0;        ll val;        for(int i=1;i<=m;i++)        {            scanf("%I64d",&val);            if(val>0&&val<n)                num[cnt++]=val;        }        //***枚举二进制***        for(int i=1;i<(1<<cnt);i++)//把cnt个数看作cnt位,每位是0或者1        {            //下面就是求状态i里面有多少个1,也就是重叠多少次,用k表示            int k=0;            ll lcm=1;            for(int j=0;j<cnt;j++)            {                if(i&(1<<j))                {                    k++;                    lcm=LCM(lcm,num[j]);//求出这k个数的最小公倍数                }            }            if(k&1)                ans+=(n-1)/lcm;            else                ans-=(n-1)/lcm;        }        printf("%I64d\n",ans);    }    return 0;}
原创粉丝点击