HDU - 1796 How many integers can you find

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

解题思路:容斥原理地简单应用。先找出1...n内能被集合中任意一个元素整除的个数,再减去能被集合中任意两个整除的个数,即能被它们两只的最小公倍数整除的个数,因为这部分被计算了两次,然后又加上三个时候的个数,然后又减去四个时候的倍数

有几点需要注意:

①m里的值可能是0

②m的值可能不互质,这时候取数的时候不能直接相乘,要求LCM( )(比如(2,4),能被4整除的都能被2整除,这部分数加了两次,减去2和4的最小公倍数即能被4整除的这部分数)

③m里的数可能大于等于n

④n要减一

AC代码:

#include<iostream>
using namespace std;
int n,m,q[30];
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
    return a/gcd(a,b)*b;//先除在乘,避免超int 
}
int nop()//容斥原理 
{
    int flag,num,sum=0;
    for(int i=1;i<(1<<m);i++)//二进制枚举
    {
        flag=0;
        num=1;
        for(int j=0;j<m;j++)
        {
            if(i >> j & 1)
            {
                flag++;//计数 
                num=lcm(num,q[j]);
            }
        }
        if(flag&1)//奇加偶减 
            sum+=n/num;
        else
            sum-=n/num;
    }
    return sum;
}
int main()
{
    while(cin>>n>>m)
    {
        n--;
        for(int i=0;i<m;i++)
        {
            cin>>q[i];
            if(q[i]<1||q[i]>=n)//大于n和小于1的删除 
            {
                i--;
                m--;
            }
        }
        int ans=nop();
        cout<<ans<<endl;
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/qq_40707370/article/details/82502403
今日推荐