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

Solution:

题目中让求能被m集合中任意一个数整除的数的个数(1~n中),算是很裸的一个容斥原理模板题。

我们记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 <cstring>

using namespace std;

typedef long long ll;

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll n, m;
ll a[50];

int main()
{
    while(cin >> n >> m)
    {
        ll x;
        int top = 0;
        for(int i = 0; i < m; ++ i)
        {
            cin >> x;
            if(x != 0)                  //因为可能有0的存在,而且0对答案没有影响,也就是任何数都不能和0除。
                a[top++] = x;
        }
        ll ans = 0;
        for(int i = 1; i < (1 << top); ++ i)
        {
            ll cnt = 0, temp;
            for(int j = 0; j < top; ++ j)
            {
                if((1 << j) & i)
                {
                    cnt++;
                    if(cnt >= 2)
                    {
                        temp = temp * a[j] / gcd(temp, a[j]);
                    }
                    else
                    {
                        temp = a[j];
                    }
                }
            }
            if(cnt % 2)
            {
                ans += (n - 1) / temp;   //1到n - 1这些数中能被temp整除的个数
            }
            else
            {
                ans -= (n - 1) / temp;
            }
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/84671229