1. 程式人生 > >容斥原理詳細介紹

容斥原理詳細介紹



翻譯:[email protected]

對容斥原理的描述

容斥原理是一種重要的組合數學方法,可以讓你求解任意大小的集合,或者計算複合事件的概率。

描述

       容斥原理可以描述如下:

         要計算幾個集合並集的大小,我們要先將所有單個集合的大小計算出來,然後減去所有兩個集合相交的部分,再加回所有三個集合相交的部分,再減去所有四個集合相交的部分,依此類推,一直計算到所有集合相交的部分。

關於集合的原理公式

      上述描述的公式形式可以表示如下:

        

     它可以寫得更簡潔一些,我們將B作為所有Ai的集合,那麼容斥原理就變成了:

        

這個公式是由 De Moivre (Abraham de Moivre)提出的。

關於維恩圖的原理

       用維恩圖來表示集合A、B和C:

       

那麼的面積就是集合ABC各自面積之和減去  的面積,再加上的面積。


由此,我們也可以解決n個集合求並的問題。

關於概率論的原理

       設事件代表發生某些事件的概率(即發生其中至少一個事件的概率),則:

  

這個公式也可以用B代表Ai的集合:


容斥原理的證明

       我們要證明下面的等式:

       

其中B代表全部Ai的集合

我們需要證明在Ai集合中的任意元素,都由右邊的算式被正好加上了一次(注意如果是不在

Ai集合中的元素,是不會出現在右邊的算式中的)。

假設有一任意元素在kAi集合中(k>=1),我們來驗證這個元素正好被加了一次:

size(C)=1時,元素x被加了k次。

size(C)=2時,元素x被減了C(2,k)次,因為在k個集合中選擇2個,其中都包含x

size(C)=3時,元素x被加了C(3,k)次。

         ……

size(C)=k時,元素x被加/減了C(k,k)次,符號由sign(-1)^(k-1)決定。

size(C)>k時,元素x不被考慮。

然後我們來計算所有組合數的和。

         

由二項式定理,我們可以將它變成

    

我們把

x取為1,這時表示1-T(其中Tx被加的總次數),所以,證明完畢。

對於實際問題的應用

       容斥原理的理論需要通過例子才能很好的理解。

         首先,我們用三個簡單的例子來闡釋這個理論。然後會討論一些複雜問題,試看如何用容斥原理來解決它們。

         其中的“尋找路徑數”是一個特殊的例子,它反映了容斥問題有時可以在多項式級複雜度內解決,不一定需要指數級。

一個簡單的排列問題

       由0到9的數字組成排列,要求第一個數大於1,最後一個數小於8,一共有多少種排列?

         我們可以來計算它的逆問題,即第一個元素<=1或者最後一個元素>=8的情況。

         我們設第一個元素<=1時有X組排列,最後一個元素>=8時有Y組排列。那麼通過容斥原理來解決就可以寫成:

       

經過簡單的組合運算,我們得到了結果:

         

然後被總的排列數10!減,就是最終的答案了。

(0,1,2)序列問題

       長度為n的由數字0,1,2組成的序列,要求每個數字至少出現1次,這樣的序列有多少種?

         同樣的,我們轉向它的逆問題。也就是不出現這些數字的序列 不出現其中某些數字的序列。

         我們定義Ai(i=0…2)表示不出現數字i的序列數,那麼由容斥原理,我們得到該逆問題的結果為:


可以發現每個Ai的值都為2^n(因為這些序列中只能包含兩種數字)。而所有的兩兩組合為1(它們只包含1種數字)。最後,三個集合的交集為0。(因為它不包含數字,所以不存在)

        要記得我們解決的是它的逆問題,所以要用總數減掉,得到最終結果:

         

方程整數解問題

       給出一個方程:

       

其中

求這個方程的整數解有多少組。

我們先不去理會xi<=8的條件,來考慮所有正整數解的情況。這個很容易用組合數來求解,我們要把20個元素分成6組,也就是新增5塊“夾板”,然後在25個位置中找5塊“夾板”的位置。

         

然後通過容斥原理來討論它的逆問題,也就是x>=9時的解。

我們定義Akxk>=9並且其他xi>=0時的集合,同樣我們用上面的新增“夾板”法來計算Ak的大小,因為有9個位置已經被xk所利用了,所以:

         

然後計算兩個這樣的集合AkAp的交集:

         

因為所有x的和不能超過20,所以三個或三個以上這樣的集合時是不能同時出現的,它們的交集都為0。最後我們用總數剪掉用容斥原理所求逆問題的答案,就得到了最終結果:

         

求指定區間內與n互素的數的個數:

       給出整數n和r。求區間[1;r]中與n互素的數的個數。

         去解決它的逆問題,求不與n互素的數的個數。

         考慮n的所有素因子pi(i=1…k)

         在[1;r]中有多少數能被pi整除呢?它就是:

       

然而,如果我們單純將所有結果相加,會得到錯誤答案。有些數可能被統計多次(被好幾個素因子整除)。所以,我們要運用容斥原理來解決。

我們可以用2^k的演算法求出所有的pi組合,然後計算每種組合的pi乘積,通過容斥原理來對結果進行加減處理。

關於此問題的最終實現:

<span style="font-size:24px;">int solve (int n, int r) {

        vector<int> p;

        for (int i=2; i*i<=n; ++i)

               if (n % i == 0) {

                       p.push_back (i);

                       while (n % i == 0)

                               n /= i;

               }

        if (n > 1)

               p.push_back (n);

 

        int sum = 0;

        for (int msk=1; msk<(1<<p.size()); ++msk) {

               int mult = 1,

                       bits = 0;

               for (int i=0; i<(int)p.size(); ++i)

                       if (msk & (1<<i)) {

                               ++bits;

                               mult *= p[i];

                       }

 

               int cur = r / mult;

               if (bits % 2 == 1)

                       sum += cur;

               else

                       sum -= cur;

        }

 

        return r - sum;

}

</span>

演算法的複雜度為 

求在給定區間內,能被給定集合至少一個數整除的數個數

       給出n個整數ai和整數r。求在區間[1;r]中,至少能被一個ai整除的數有多少。

         解決此題的思路和上題差不多,計算ai所能組成的各種集合(這裡將集合中ai的最小公倍數作為除數)在區間中滿足的數的個數,然後利用容斥原理實現加減。

         此題中實現所有集合的列舉,需要2^n的複雜度,求解lcm需要O(nlogr)的複雜度。

能滿足一定數目匹配的字串的個數問題

       給出n個匹配串,它們長度相同,其中有一些’?’表示待匹配的字母。然後給出一個整數k,求能正好匹配k個匹配串的字串的個數。更進一步,求至少匹配k個匹配串的字串的個數。

         首先我們會發現,我們很容易找到能匹配所有匹配串的字串。只需要對比所有匹配串,去在每一列中找出現的字母(或者這一列全是’?’,或者這一列出現了唯一的字母,否則這樣的字串就存在),最後所有字母組成的單詞即為所求。

         現在我們來學習如何解決第一個問題:能正好匹配k個匹配串的字串。

         我們在n個匹配串中選出k個,作為集合X,統計滿足集合X中匹配的字串數。求解這個問題時應用容斥原理,對X的所有超集進行運算,得到每個X集合的結果:

       

此處f(Y)代表滿足匹配集合Y的字串數。

如果我們將所有的ans(X)相加,就可以得到最終結果:

         

這樣,就得到了一個複雜度的解法。

這個演算法可以作一些改進,因為在求解ans(X)時有些Y集合是重複的。

回到利用容斥原理公式可以發現,當選定一個Y時,所有 X的結果都是相同的,其符號都為。所以可以用如下公式求解:

         

這樣就得到了一個複雜度的解法。

現在我們來求解第二個問題:能滿足至少k個匹配的字串有多少個。

顯然的,我們可以用問題一的方法來計算滿足kn的所有結果。問題一的結論依然成立,不同之處在於這個問題中的X不是大小都為k的,而是>=k的所有集合。

如此進行計算,最後將f(Y)作為另一個因子:將所有的ans做和,有點類似二項式展開:



根據這個公式,可以將前面的結果進行化簡:


那麼,對於這個問題,我們也得到了一個的解法:


路徑的數目問題

       在一個方格陣中,有k個格子是不可穿越的牆。一開始在格子(1,1)(最左下角的格子)中有一個機器人。這個機器人只能向上或向右行進,最後它將到達位於格子(n,m)的籠子裡,其間不能經過障礙物格子。求一共有多少種路線可以到達終點。

為了方便區分所有障礙物格子,我們建立座標系,用(x,y)表示格子的座標。

首先我們考慮沒有障礙物的時候:也就是如何求從一個點到另一個點的路徑數。如果從一個點在一個方向要走x個格子,在另一個方向要走y個格子,那麼通過簡單的組合原理可以得知結果為:

         

現在來考慮有障礙物時的情況,我們可以利用容斥原理:求出至少經過一個障礙物時的路徑數。

對於這個例子,你可以列舉所有障礙物的子集,作為需要要經過的,計算經過該集合障礙物的路徑數(求從原點到第一個障礙物的路徑數、第一個障礙物到第二個障礙物的路徑數最後對這些路徑數求乘積),然後通過容斥原理,對這些結果作加法或減法。

然而,它是一個非多項式的解法,複雜度。下面我們將介紹一個多項式的解法

我們運用動態規劃:令d[i][j]代表從第i個點到第j個點,不經過任何障礙物時的路徑數(當然除了ij)。那麼我們總共需要k+2個點,包括k個障礙物點以及起點和終點。

首先我們算出從i點到j點的所有路徑數,然後減掉經過障礙物的那些“壞”的路線。讓我們看看如何計算“壞”的路線:列舉ij之間的所有障礙物點i<l<j,那麼從ij的“壞”路徑數就是所有d[i][l]d[l][j]的乘積最後求和。再被總路徑數減掉就是d[i][j]的結果。

我們已經知道計算總路徑數的複雜度為 ,那麼該解法的總複雜度為

(譯註:當然也有O(nm)dp解法,根據nmk的值可以採取適當的解法)

素數四元組的個數問題

       給出n個數,從其中選出4個數,使它們的最大公約數為1,問總共有多少中取法。

我們解決它的逆問題:求最大公約數d>1的四元組的個數。

運用容斥原理,將求得的對於每個d的四元組個數的結果進行加減。

         

其中deg(d)代表d的質因子個數,f(d)代表四個數都能被d整除的四元組的個數。

求解f(d)時,只需要利用組合方法,求從所有滿足被d整除的ai中選4個的方法數。

然後利用容斥原理,統計出所有能被一個素數整除的四元組個數,然後減掉所有能被兩個素數整除的四元組個數,再加上被三個素數整除的四元組個數

和睦數三元組的個數問題

       給出一個整數 。選出a, b, c (其中2<=a<b<c<=n),組成和睦三元組,即:

· 或者滿足   

·或者滿足

首先,我們考慮它的逆問題:也就是不和睦三元組的個數。

然後,我們可以發現,在每個不和睦三元組的三個元素中,我們都能找到正好兩個元素滿足:它與一個元素互素,並且與另一個元素不互素。

所以,我們只需列舉2n的所有數,將每個數的與其互素的數的個數和與其不互素的數的個數相乘,最後求和併除以2,就是要求的逆問題的答案。

現在我們要考慮這個問題,如何求與2到n這些數互素(不互素)的數的個數。雖然求解與一個數互素數的個數的解法在前面已經提到過了,但在此並不合適,因為現在要求2到n所有數的結果,分別求解顯然效率太低。

所以,我們需要一個更快的演算法,可以一次算出2到n所有數的結果。

在這裡,我們可以使用改進的埃拉托色尼篩法

·首先,對於2n的所有數,我們要知道構成它的素數中是否有次數大於1的,為了應用容斥原理,我們還有知道它們由多少種不同的素數構成。

對於這個問題,我們定義陣列deg[i]:表示i由多少種不同素數構成,以及good[i]:取值true或false,表示i包含素數的次數小於等於1是否成立。

再利用埃拉托色尼篩法,在遍歷到某個素數i時,列舉它在2到n範圍內的所有倍數,更新這些倍數的deg[]值,如果有倍數包含了多個i,那麼就把這個倍數的good[]值賦為false。

·然後,利用容斥原理,求出2n每個數的cnt[i]:在2n中不與i互素的數的個數。

回想容斥原理的公式,它所求的集合是不會包含重複元素的。也就是如果這個集合包含的某個素數多於一次,它們不應再被考慮。

所以只有當一個數i滿足good[i]=true時,它才會被用於容斥原理。列舉i的所有倍數i*j,那麼對於i*j,就有N/i個與i*j同樣包含i(素數集合)的數。將這些結果進行加減,符號由deg[i](素數集合的大小)決定。如果deg[i]為奇數,那麼我們要用加號,否則用減號。

程式實現:

<span style="font-size:24px;">int n;

bool good[MAXN];

int deg[MAXN], cnt[MAXN];

 

long long solve() {

         memset (good, 1, sizeof good);

         memset (deg, 0, sizeof deg);

         memset (cnt, 0, sizeof cnt);

 

         long long ans_bad = 0;

         for (int i=2; i<=n; ++i) {

                 if (good[i]) {

                          if (deg[i] == 0) deg[i] = 1;

                          for (int j=1; i*j<=n; ++j) {

                                   if (j > 1 && deg[i] == 1)

                                            if (j % i == 0)

                                                    good[i*j] = false;

                                            else

                                                    ++deg[i*j];

                                   cnt[i*j] += (n / i) * (deg[i]%2==1 ? +1 : -1);

                          }

                 }

                 ans_bad += (cnt[i] - 1) * 1ll * (n - cnt[i] - 1);

         }

         return (n-1) * 1ll * (n-2) * (n-3) / 6 - ans_bad / 2;

}</span>

最終演算法的複雜度為 ,因為對於大部分i都要進行n/i次列舉。

錯排問題

       我們想要證明如下的求解長度為n序列的錯排數的公式:

      

它的近似結果為:

         

(此外,如果將這個近似式的結果向其最近的整數舍入,你就可以得到準確結果)

我們定義Ak:在長度為n的序列中,有一個不動點位置為k(1<=k<=n)時的序列集合。

現在我們運用容斥原理來計算至少包含有一個不動點的排列數,要計算這個,我們必須先算出所有Ak、以及它們的交集的排列數。




因為我們知道當有x個不動點時,所有不動點的位置是固定的,而其它點可以任意排列。

用容斥原理對結果進行帶入,而從n個點中選x個不動點的組合數為,那麼至少包含一個不動點的排列數為:


那麼不包含不動點(即錯排數)的結果就是:


化簡這個式子,我們得到了錯排數的準確式和近似式:


(因為括號中是泰勒展開式的前n+1項)

用這個式子也可以解決一些類似的問題,如果現在求有m個不動點的排列數,那麼我們可以對上式進行修改,也就是將括號中的累加到1/n!改成累加到1/(n-m)!

題目描述

1n範圍內能被568整除的數的個數。(0<n<10^7輸入

相關推薦

原理詳細介紹

 翻譯:[email protected] 對容斥原理的描述 容斥原理是一種重要的組合數學方法,可以讓你求解任意大小的集合,或者計算複合事件的概率。 描述        容斥原理可以描述如下:          要計算幾個集合並集的大小,我們要先將所有單個集合

原理 —— 求1~n有多少個數與k互質(二進位制演算法詳細解釋&模板)

這裡有一道經典的例題,可以看一下:點選開啟連結 這裡的n可能要大於k的,所以不能用尤拉函式去做。 我們首先把k分解質因數,儲存到p陣列中,num表示質因子的數量。 void pr(int k) //求k的質因子 { num = 0; for (int i = 2 ;

POJ 1091 原理

.org 質因子 blank dfs tar cin href strong 元組 鏈接: http://poj.org/problem?id=1091 題意: 給你兩個正整數n,m,讓你求長度為n+1的滿足條件的一個等式:a[1]*x1+a[2]*x2+a[3]*x

原理

clu images class 又是 對象 title href 推理 計算 容斥原理(Inclusion–exclusion principle),是指在計數時,必須註意無一重復,無一遺漏,為了使重疊部分不被重復計算,人們研究出一種新的計數方法。這種方法的基

POJ 2773 原理

for log cto tor ans 個數 ret num void 鏈接: http://www.cnblogs.com/MashiroSky/p/5913989.html 題意: 給出兩個數m,k,要求求出從1開始與m互質的第k個數。 題解: 二分一個答案m

{原理}

.com lld hide mes problem fine efi lose -a 題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1284 比較基礎練一下。 1 #include

POJ3904 Sky Code【原理

define 原理 tail n-1 pop blog soft ace tdi 題目鏈接: http://poj.org/problem?id=3904 題目大意: 給你N個整數。從這N個數中選擇4個數,使得這四個數的公約數為1。求滿足條件的 四元組個數。

洛谷P1450 [HAOI2008]硬幣購物 動態規劃 + 原理

string -1 line sum mes 開始 clas 完全背包 預處理 洛谷P1450 [HAOI2008]硬幣購物 動態規劃 + 容斥原理 1、首先我們去掉限制 假設 能夠取 無數次 也就是說一開始把他當做完全背包來考慮 離線DP 預處理 復雜度 4*v

hdu 1695 GCD(歐拉函數+原理)

spi fin clu init mod long long tac push_back gcd http://acm.hdu.edu.cn/showproblem.php?pid=1695 非常經典的題。同一時候感覺也非常難。 在區間[a,b]和[c,d]內分

洛谷1002 原理+dfs OR DP

amp define its name sign pri last += include //By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long lon

TopCoder SRM 717 Div2 C.DerangementsDiv2[數論][原理][錯排]

long max math 需要 linker nal tex 排列 lin 題意:從1到n+m的數組中選m個數字且每個數字和在原數組中下標不同,求方案數。例如 n=1 m = 2 則存在{2,1},{2,3},{3,1} 題解:錯排問題模板 下面是使用容斥原理推導的過程

[原理] hdu 1796 How many integers can you find

pos lcm 一個 每一個 fin memset 而不是 std != 題意: 給一個N。然後給M個數,問1~N-1裏面有多少個數能被這M個數中一個或多個數整除。 思路: 首先要N-- 然後對於每一個數M 事實上1~N-1內能被其整除的 就是有(N-1)/

POJ2773 Happy 2006【原理

sca problem article 容斥原理 lan /tmp .org family pop 題目鏈接: http://poj.org/problem?id=2773 題目大意: 給你兩個整數N和K。找到第k個與N互素的數(互素的數從小到大排

洛谷 P2986 [USACO10MAR]Great Cow Gat…(樹形dp+原理)

nco more printf ide eva gre ans names get P2986 [USACO10MAR]偉大的奶牛聚集Great Cow Gat… 題目描述 Bessie is planning the annual Great Cow G

HDU 5794 A Simple Chess(楊輝三角+原理+Lucas)

exgcd -i -- || 兩種方法 sizeof put amp mem 題目鏈接 A Simple Chess 打表發現這其實是一個楊輝三角…… 然後發現很多格子上方案數都是0 對於那寫可能可以到達的點(先不考慮障礙點),我們先叫做有

bzoj 2005 能量采集 - 原理

100% itl memset blog read 線段 太陽 break als 棟棟有一塊長方形的地,他在地上種了一種能量植物,這種植物可以采集太陽光的能量。在這些植物采集能量後, 棟棟再使用一個能量匯集機器把這些植物采集到的能量匯集到一起。 棟棟的植物種得非常整

【BZOJ 3505】 [Cqoi2014]數三角形 原理+排列組合+GCD

貢獻 def pri 組合 ans 矩形 排列組合 排列 ret 我們先把所有三角形用排列組合算出來,再把一行一列上的三點共線減去,然後我們只觀察向右上的三點共線,向左上的乘二即可,我們發現我們如果枚舉所有的兩邊點再乘中間點的個數(GCD),那麽我們發現所有的兩邊點都會形成

Codeforces 839D Winter is here - 暴力 - 原理

second you cti span http enter fine creat 大小為n Winter is here at the North and the White Walkers are close. John Snow has an army consist

【bzoj3782】上學路線 dp+原理+Lucas定理+中國剩余定理

只需要 輸出 容斥 題解 質數 不為 上學路線 sort 短路徑 題目描述 小C所在的城市的道路構成了一個方形網格,它的西南角為(0,0),東北角為(N,M)。小C家住在西南角,學校在東北角。現在有T個路口進行施工,小C不能通過這些路口。小C喜歡走最短的路徑到達目的地,因

Codeforces Round #428 (Div. 2) D. Winter is here[數論II][原理]

note efi force its eps page http ref esp 傳送門:http://codeforces.com/contest/839/problem/D Examples input 33 3 1 output 12 inp