日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

容斥原理(二进制枚举)

發布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 容斥原理(二进制枚举) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在計數時,必須注意無一重復,無一遺漏。為了使重疊部分不被重復計算,人們研究出一種新的計數方法,這種方法的基本思想是:先不考慮重疊的情況,把包含于某內容中的所有對象的數目先計算出來,然后再把計數時重復計算的數目排斥出去,使得計算的結果既無遺漏又無重復,這種計數的方法稱為容斥原理。

兩個集合的容斥關系公式:A∪B = A+B – A∩B (∩:重合的部分)?
三個集合的容斥關系公式:A∪B∪C = A+B+C – A∩B – B∩C – C∩A +A∩B∩C?
詳細推理如下:?
1、 等式右邊改造 = {[(A+B – A∩B)+C – B∩C] – C∩A }+ A∩B∩C?
2、文氏圖分塊標記如右圖圖:1245構成A,2356構成B,4567構成C?
3、等式右邊()里指的是下圖的1+2+3+4+5+6六部分:?
那么A∪B∪C還缺部分7。?
4、等式右邊[]號里+C(4+5+6+7)后,相當于A∪B∪C多加了4+5+6三部分,?
減去B∩C(即5+6兩部分)后,還多加了部分4。?
5、等式右邊{}里減去C∩A (即4+5兩部分)后,A∪B∪C又多減了部分5,?
則加上A∩B∩C(即5)剛好是A∪B∪C。?

在這里我要說的是一個二進制枚舉

正文

所謂二進制枚舉 就是一種暴力的方式,用0,1來代表一個數字存在或不存在。?
例如 0101 可以理解為 第一個物品要了,第二個不要,第三個要了,第四個不要。?
那么這個和容斥原理有什么關系呢??
我們都知道容斥原理的公式為:?
?
可能很多剛剛接觸的小伙伴不太了解,其實有很多的問題需要容斥來解決,我舉一個例子:?
如果求100以內的除了 2的倍數 和 3的倍數的數 有多少個,我們可以很容易知道 2的倍數的個數是100/2,而3的倍數是100/3,“答案“是100-50-33 = 17?
這顯然是不對的 以6為例 6既是2的倍數也是三的倍數,顯然減重了。 但是我們有人就要說了,我可以每個數都判斷一下。

#include<iostream> using namespace std; int main(){int ans = 0;for(int i = 1;i<+100;i++){if(i%2==0 || i%3==0){ans++;}}cout<<ans<<endl; }

但是,當n很大的時候,要O(n)時間復雜度。顯然是不符合實際的。

這里我先引入容斥原理的概念?
我們回到剛才的那個問題,我們有沒有辦法解決減重的情況??
這里我們就要運用容斥原理解決這個問題了,?
100-2的倍數-3的倍數+6的倍數?
減重復的加回來就好了,這個6是二和三的最小公倍數?
好了這個問題我們已經很好的解決了,但是我們真的解決問題了嗎??
我們在舉一個例子 :?
100以內的數 求 2 3 5 7 11 的倍數,我們還是用剛才方法,?
2的倍數+3的倍數+5的倍數+7的倍數+11的倍數- 。。。。。。。?
這個時候我們犯難了 要減的有2∩3,減2∩5......還要加回減多的2∩3∩5.....
太麻煩了,明明這么簡單的一道題,怎么解決??
這里我們就要引入二進制枚舉的概念了:?

根據上面的公式:

上面的公式有2^m-1種情況。

我們把二進制表示2,3,5,7,11五個數。為什么可以這樣呢?

這就是二進制枚舉的好處了。因為有5個數,所以5個數組成的倍數有2^5-1種。

比如2的倍數:我們表示為00001

? ? ? 2∩3的倍數:00011

? ? ? 5∩11的倍數:10100

就是說,1~2^5每一個二進制位(0表示沒選,1表示選定)表示2,3,5,7,11的選不選定。初學者還是有點難理解的,認認真真看代碼,看是怎么實現的,花點時間認真弄明白。

#include<iostream> #include<stdio.h> #include<math.h> using namespace std;int a[] = {2,3,5,7,11}; int main(){int n;int lena = 5;while(~scanf("%d",&n)){int ans = 0;for(int i = 1;i<(1<<lena);i++){ ///每個數都有2種狀態 ,在或不在 在本題中的意思是2,3,5,7,11的倍數或不是, ///一共有2^5-1種可能int tmp=0;int lcm=1;for(int j = 0;j<lena;j++){if((1<<j)&i){///選第j個b倍數子;與i的二進制的第j位比較,看是否為1,是則選中tmp++;//標志變量計算i中1的個數,也就是倍數的個數lcm*=a[j];///相乘 }}if(tmp%2==1) ans+=n/lcm; //奇數是加 偶數是減else ans-=n/lcm;printf("%d\n",ans);}cout<<ans<<endl;} }

?

?

簡單應用:

由0 到9 數字組成排列,要求第一個數大于1,最一個數小于8,一共有幾種排列。?
思路:?
求逆問題,第一個數<=1,最后一個數>=8?
由容斥原理,?
則有 事件A(第一個數<=1) = 2*9!, 事件B(最后一個數>=8) = 2*9!, 事件C(A交B) C= 2*2*8!?
所以逆問題的結果是 A+B-C?
則問題的答案是 10!-(A+B-C)。

?

經典例題:

例題1:

給出一個數N,求1至N中,有多少個數不是2 3 5 7的倍數。 例如N = 10,只有1不是2 3 5 7的倍數。
  • 1
  • 2

Input?
輸入1個數N(1 <= N <= 10^18)。?
Output?
輸出不是2 3 5 7的倍數的數共有多少。?
Sample Input

10
  • 1
  • 2

Sample Output

1
  • 1
  • 2

包含排斥原理,就是那道公式。?
四個圓圈的并,是四個的單獨面積的總和,減去四個分別兩兩相交的兩層的面積,加上四個分別三三相交的三層的面積,再減去四個相交的面積。最后就是并了。這道題,也是這個意思,只不過數多一點。

?

#include<stdio.h> int main(){long long num=0,n,a,b,c,d,ab,ac,ad,bc,bd,cd,abc,abd,acd,bcd,abcd;scanf("%lld",&n);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;abd=n/42;acd=n/70;bcd=n/105;abcd=n/210;num=a+b+c+d-ab-ac-ad-bc-bd-cd+abc+abd+acd+bcd-abcd;printf("%I64d\n",n-num); }


這次還有就是看數據量可不可以暴力過,可以的話,直接暴力就解決了。這就是考察你會不會進行估算。

自己可以用二進制枚舉寫一下。

?

總結

以上是生活随笔為你收集整理的容斥原理(二进制枚举)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。