现在的位置: 首页 > 综合 > 正文

组合数学第三发 容斥原理 hdu 1796

2018年04月24日 ⁄ 综合 ⁄ 共 1854字 ⁄ 字号 评论关闭

容斥原理是对集合的运算。

举个例子三个集合的容斥原理: A ∪ B ∪ C   =   A +  B + C   -  A ∩ B   -   B ∩ C   -   C ∩ A   + A ∩ B ∩ C.

多个集合的容斥原理:\left|\bigcup_{i=1}^n A_i\right|=\sum_{i=1}^n\left|A_i\right|-\sum_{i,j\,:\,i\neq j}\left|A_i\cap A_j\right|+\sum_{i,j,k\,:\,i\neq j\neq k}\left|A_i\cap A_j\cap A_k\right|-\ \cdots\cdots\ \pm \left|A_1\cap\cdots\cap A_n\right|

hdu 1796 

How many integers can you find

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
 
在总数以下的所有数为一个集合要寻找集合中所求子集。
子集是所有给出数字的倍数集合的并集,典型的容斥原理。
用DFS的思想来举出所有集合的情况,有奇数个数的集合中的元素数加进去,有偶数个数的集合中的元素数减价去,最后即可求出并集。
刚开始交代码时候 judge结果是
          Runtime Error            
(INTEGER_DIVIDE_BY_ZERO)
这个略坑,所给的数竟然有0,改掉以后就变WA了,就知道代码有点挫,有可能超int了,就改成__int64就过了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 15
#define INF 1<<25
typedef long long ll;
using namespace std;
__int64 num,ans;
__int64 aa[maxn],lim,tot,s;
bool vv[maxn];
__int64 gcd(__int64 x,__int64 y)
{
    return !y?x:gcd(y,x%y);
}
__int64 lcm(__int64 x,__int64 y)
{
    return x*y/gcd(x,y);
}
__int64 dfs(__int64 x,__int64 y)
{
    vv[x]=1;
    s++;
    if(s==y)
    {
        __int64 rec=1;
        for(int i=0; i<tot; i++)
            if(vv[i])
                rec=lcm(rec,aa[i]);
        if(y%2)
            ans+=lim/rec;
        else ans-=lim/rec;
        return 0;
    }
    for(int i=x; i<tot; i++)
    {
        if(!vv[i])
        {
            dfs(i,y);
            vv[i]=0;
            s--;
        }

    }
}
int main()
{
    while(scanf("%I64d%I64d",&lim,&tot)!=EOF)
    {
        memset(aa,0,sizeof(aa));
        lim--;
        int ii=0;
        for(int i=0; i<tot; i++)
        {
            int xx;
            scanf("%d",&xx);
            if(xx)
            aa[ii++]=xx;
        }
        tot=ii;
        ans=0;
        for(int i=1; i<=tot; i++)
        {
            for(int j=0; j<tot; j++)
            {
                memset(vv,0,sizeof(vv));
                s=0;
                dfs(j,i);
            }
        }
        printf("%I64d\n",ans);
    }
}

抱歉!评论已关闭.