一、容斥原理
在計數時,要保證無一重複,無一遺漏。爲了使重疊部分不被重複計算,在不考慮重疊的情況下,把包含於某內容中的所有對象的數目先計算出來,然後再把計數時重複計算的數目排斥出去,使得計算的結果既無遺漏又無重複,這種計數的方法稱爲容斥原理。
1.容斥原理1——兩個集合的容斥原理
如果被計數的事物有A、B兩類,那麼,先把A、B兩個集合的元素個數相加,發現既是A類又是B類的部分重複計算了一次,所以要減去。如圖所示:
公式:A∪B=A+B-A∩B
總數=兩個圓內的-重合部分的
2.容斥原理2——三個集合的容斥原理
如果被計數的事物有A、B、C三類,那麼,將A、B、C三個集合的元素個數相加後發現兩兩重疊的部分重複計算了1次,三個集合公共部分被重複計算了2次。
如圖所示,灰色部分A∩B-A∩B∩C、B∩C-A∩B∩C、C∩A-A∩B∩C都被重複計算了1次,黑色部分A∩B∩C被重複計算了2次,因此總數A∪B∪C=A+B+C-(A∩B-A∩B∩C)-(B∩C-A∩B∩C)-(C∩A-A∩B∩C)-2A∩B∩C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C。即得到:
公式:A∪B∪C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C
總數=三個圓內的-重合兩次的+重合三次的
上面只是簡單介紹一下容斥原理,那麼代碼如何寫呢
就可以看看一篇講的比較好的博客,裏面有具體的實現方法還包括歐拉函數和抽屜原理的講解。
點擊打開博客http://blog.csdn.net/qq_36368339/article/details/70217849
附上兩個實際的例子:
題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1284
我只是單純的應用到了這個原理,代碼寫得有點直接。
正確代碼:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e18;
int main()
{
LL n;
while(~scanf("%lld",&n))
{
LL a,b,c,d,ab,ac,ad,bc,bd,cd,abc,acd,abd,bcd,abcd;//15
a=n/2;
b=n/3;
c=n/5;
d=n/7;
ab=n/6;
ac=n/10;
ad=n/14;
bc=n/15;
bd=n/21;
cd=n/35;
abc=n/30;
acd=n/70;
abd=n/42;
bcd=n/105;
abcd=n/210;
abc=abc-abcd;//僅包括同時能被2,3,5整除的數,下面得到的結果依次類推
abd=abd-abcd;
acd=acd-abcd;
bcd=bcd-abcd;
ab=ab-(abc+abd+abcd);
ac=ac-(abc+acd+abcd);
ad=ad-(abd+acd+abcd);
bc=bc-(abc+bcd+abcd);
bd=bd-(abd+bcd+abcd);
cd=cd-(acd+bcd+abcd);
a=a-(ab+ac+ad+abc+abd+acd+abcd);
b=b-(ab+bc+bd+abc+abd+bcd+abcd);
c=c-(ac+bc+cd+abc+acd+bcd+abcd);
d=d-(ad+bd+cd+abd+acd+bcd+abcd);
LL ans;
ans=n-(a+b+c+d+ab+ac+ad+bc+bd+cd+abc+abd+acd+bcd+abcd);//此時的各部分之間沒有重疊
printf("%lld\n",ans);
}
return 0;
}
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6106
容斥原理
正確代碼:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,maxn=-1;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int a,b,c,d,e,f,g,ab,bc,ac,abc;
scanf("%d%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f,&g);
//接下來的操作將各部分之間重複的排除
d-=g;//ab
e-=g;//bc
f-=g;//ac
a=a-(d+f+g);
b=b-(d+e+g);
c=c-(e+f+g);
if(a<0||b<0||c<0||d<0||e<0||f<0||g<0)//判斷數據是否有誤
continue;
int s=a+b+c+d+e+f+g;
if(s>maxn)
maxn=s;
}
printf("%d\n",maxn);
}
return 0;
}