容斥原理是对集合的运算。
举个例子三个集合的容斥原理: A ∪ B ∪ C = A + B + C - A ∩ B - B ∩ C - C ∩ A + A ∩ B ∩ C.
多个集合的容斥原理:
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.
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); } }