容斥原理學習
阿新 • • 發佈:2019-01-23
1.何為容斥原理?
在計數時,必須注意沒有重複,沒有遺漏。為了使重疊部分不被重複計算,人們研究出一種新的計數方法,這種方法的基本思想是:先不考慮重疊的情況,把包含於某內容中的所有物件的數目先計算出來,然後再把計數時重複計算的數目排斥出去,使得計算的結果既無遺漏又無重複,這種計數的方法稱為容斥原理
2.如何用容斥原理?
結果的個數為一個集合的話,則算出所有集合,減去兩個集合重合的部分,加上三個集合重合的部分,減去四個集合重合的部分,以此類推。
至於為何要加上三個集合的部分我們可以用溫恩圖來說明
如圖 當我們減去兩兩相交的部分時,三個部分都重合的那個被減去了三次,因此需要加上一次。
3.例題
hdu1796 大意是求 小於n 且能被m個數整除的數的個數;
poj 3904#include<iostream> using namespace std; int a[100],ans,n,cc; int gcd(int a,int b){ return !b?a:gcd(b,a%b); } int lcm(int a,int b){ return a/gcd(a,b)*b; } void dfs(int lc,int num,int i,int cnt){ if(num==cnt){ lc = (n-1)/lc; num&1?ans+=lc:ans-=lc; return ; } if (i>=cc) return; int tmp=lcm(lc,a[i]); dfs(tmp,num,i+1,cnt+1); if(num-cnt>cc-i-1) return; dfs(lc,num,i+1,cnt); } void cal(int m){ int cnt= 0,tmp; ans=0; for (int i=0;i<m;i++){ cin>>tmp; !tmp?tmp=0:a[cnt++]=tmp; } cc=cnt; for (int i=1;i<=cnt;i++){ dfs(1,i,0,0); } cout<<ans<<endl; } int main() { int m; while(cin>>n>>m){ cal(m); } return 0; }