zoukankan      html  css  js  c++  java
  • hdu 1796 How many integers can you find 容斥第一题

    How many integers can you find

    Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6710    Accepted Submission(s): 1946

    Problem Description
      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. 0<N<2^31,0<M<=10, 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
     


    Author
    wangye

    题目大意:给定n和一个大小为m的集合,集合元素为非负整数。为1...n内能被集合里任意一个数整除的数字个数。n<=2^31,m<=10

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #include <algorithm>
    #include <set>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long Ull;
    #define MM(a,b) memset(a,b,sizeof(a));
    const double eps = 1e-10;
    const int  inf =0x7f7f7f7f;
    const double pi=acos(-1);
    const int maxn=40000;
    
    ll gcd(ll a,ll b)
    {
        if(b==0) return a;
        else return gcd(b,a%b);
    }
    
    ll lcm(ll a,ll b)
    {
        return (a/gcd(a,b))*b;
    }
    
    int n,m,bit,mm[24],tmp,cnt;
    ll mult;
    void solve(int flag)
    {
        mult=1;bit=0;
        for(int i=0;i<cnt;i++)
           if(flag&(1<<i))
              {mult=lcm(mm[i],mult);bit++;}
    }
    
    int main()
    {
        while(~scanf("%d %d",&n,&m))
        {
            ll ans=0;n--;cnt=0;
            for(int i=0;i<m;i++)
            {
                scanf("%d",&tmp);
                if(tmp) mm[cnt++]=tmp;
            }
            for(int i=1;i<(1<<cnt);i++)
            {
                solve(i);
                int num=((ll)n)/mult;
                if(bit%2==1) ans+=num;
                else ans-=num;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }

    分析:很好的一道容斥题,分析:求出在给定区间中能被集合中任意一个数整除的点的个数,分析题目的话
    可以发现,先求出区间中所有能被集合中单个数整除的点的个数,求和后,会发现,能同时被两个数整除的点(是这两个数的最小公倍数的倍数)多算了一次,所以就减去能同时被两个数整除点的总个数,然后再加上能同时被三个点减去的点的个数.....(容斥),不过这个题目有个很大的坑点,就是必须要去0,否则不仅会导致re,而且还会直接导致错误,因为在下面这段代码中,如果cnt换成m的话。可以发现0的存在就直接导致了ans的值得变化,所以必须要在读入集合时就直接将0剔除

    for(int i=1;i<(1<<cnt);i++)
            {
                solve(i);
                int num=((ll)n)/mult;
                if(bit%2==1) ans+=num;
                else ans-=num;
            }
    
  • 相关阅读:
    自制的 MPlayer Skin
    mplayer filter 参数及效果
    可拖动的层DIV的完整源代码【转】
    Hibernate的检索方式(一)【转】
    HQL经典语句
    常适用的特效网页代码
    C#优化字符串操作【转】
    Hibernate的检索方式(二)【转】
    内联inline的使用方法【转】
    Hibernate的检索方式(三)【转】
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5656565.html
Copyright © 2011-2022 走看看