HDU 1796 Howmany 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): 5664    Accepted Submission(s): 1630


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
题意:在m个数的集合中,问在小于n的范围内有多少个数能整除m个数的集合中的数。
收获: 容斥原理两种表示方法: 1.二进制, 2.递归
1.二进制
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);
#define maxn 500
__int64 k[maxn];
__int64   gcd(__int64   b,__int64   a)
{
    return a==0?b:gcd(a,b%a);
}
int main()
{
    int  n, m;
    while(~scanf("%d%d", &n, &m))
    {
        int t;
        n--;
        int cnt = 0;
        for(int i = 0; i < m; i++)
        {
            scanf("%d", &t);
            if(t>0 && t < n)
                k[cnt++] = t;
        }
        __int64 ans = 0;
        for(int i = 1; i < 1<<cnt; i++)
        {
            int num = 0;
            __int64 lcm = 1;
            for(int j = 0; j < cnt; j++)
            {
                if(i & (1 << j))
                {
                    num++;
                    lcm = k[j]/gcd(k[j], lcm) * lcm;
                }
            }
            if(num & 1)
                ans += n/lcm;
            else
                ans -= n/lcm;
        }
        printf("%I64d
", ans);
    }
    return 0;
}

2. 递归

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;
__int64   a[30];
int n,m;
//cur表示
__int64   sum=0;
__int64   gcd(__int64   b,__int64   a)
{
    return a==0?b:gcd(a,b%a);
    //while()
}//最小公倍数
void dfs(int cur,__int64   lcm,int id)//容斥原理公式
{
    //lcm=lcm/gcd(lcm,a[cur])*a[cur];
    lcm=a[cur]/gcd(a[cur],lcm)*lcm;
    if(id&1)//运用了快速幂的方法判断奇偶
        sum+=(n-1)/lcm;
    else
        sum-=(n-1)/lcm;
       // cout<<"id = "<<id<<" : "<<sum<<endl;
    for(int i=cur+1;i<=m;i++)
        dfs(i,lcm,id+1);
}
int main()
{
    int t;
    while(~scanf("%d%d",&n,&t))
    {
        int i,x;
        m=0;
        for(i=1;i<=t;i++)
        {
            scanf("%d",&x);
            if(x)
             {
                a[++m]=x;
             }
        }
        sum=0;
        for(i=1;i<=m;i++)
            dfs(i,a[i],1);
        printf("%I64d
",sum);//容斥原理公式
       // cout<<sum<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZP-Better/p/4639606.html