容斥原理

一、容斥原理

  在計數時,要保證無一重複,無一遺漏。爲了使重疊部分不被重複計算,在不考慮重疊的情況下,把包含於某內容中的所有對象的數目先計算出來,然後再把計數時重複計算的數目排斥出去,使得計算的結果既無遺漏又無重複,這種計數的方法稱爲容斥原理。

  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;
}
發佈了131 篇原創文章 · 獲贊 13 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章