How many integers can you find HDU - 1796(容斥定理应用)

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

题意:

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

思路

我知道是容斥定理,但是不知道怎么去想;想了好长时间才想明白;
按题中给的数据 n =12,m = 2,集合为2 , 3;
首先选2: 11/2=5 ,3: 11/3=3;
然后选2,3: 11 /(2*3)=1;
容斥定理 :5+3-1=7;

关于这一题:
我们记num(x1, x2, x3…xn)为能被xi整除的数的个数(x1, x2…xn,为m集合中的数),那么最终的答案就是num(x1) + num(x2) + … + num(xn) - num(x1, x2) - num(x1, x3) - …- num(xn - 1, xn) + num(x1, x2, x3) + … +…等等,
也就是容斥公式:
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
ll a[20],b[20];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m)&&n&&m)
    {
        int cot=0;
        ll ans=0;
        for(int i=0;i<m;i++)//集合中可能含有0,所以要把0去除
        {
            scanf("%lld",&a[i]);
            if(a[i]!=0)
                b[cot++]=a[i];
        }
        for(int i=1;i<(1<<cot);i++)//一共cot个数字,所以有2^cot个选择
        {
            ll sum=1;
            ll cnt=0;
            for(int j=0;j<cot;j++)//每一种方案都判断第j个物品该不该选择
            {

                if(1&(i>>j))
                {
                    cnt++;
                    sum*=b[j]/__gcd(sum,b[j]);//求出来cnt个数的最大公约数sum,如果能被sum整除,那么一定能够被选中的数整除
                }
            }
            if(cnt&1)//如果选择了奇数个数字,那么就用加法
                 ans+=(n-1)/sum;
            else ans-=(n-1)/sum;
        }
        printf("%lld\n",ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值