題意: 已知集合A,B,C, 輸出三集合的並集。ios
容斥原理(用圖解釋)spa
∩code
∪blog
對於求三集合並集的公式:ci
A∪B∪C=A+B+C - A∩B - A∩C - B∩C + A∩B∩Cget
對於證實,我就簡單的敘述一下。string
由於求並集不能將兩集合的重複元素進行相加。而 A+B+C 沒有考慮重複元素,直接相加,顯然這是元素多加的狀況,那要還原必需要減去多加的部分,對於上圖藍色部分只加了一次,紅色部分加了兩次,綠色的部分加了三次,那麼咱們只須要使他們所有隻加一次就能獲得正確答案。it
因此咱們要執行下操做 A+B+C -(A∩B + A∩C + B∩C) ,但還不算完美,由於在這裏綠色部分被減了三次,要使把綠色部分只減一次,那麼要再加上一個綠色部分便可。io
對於求四集合並集的公式:class
A∪B∪C∪D=A+B+C+D - A∩B - B∩C - C∩A - A∩D - B∩D - C∩D + A∩B∩C + A∩B∩D + A∩C∩D + B∩C∩D - A∩B∩C∩D ( 規律 集合數 奇加偶減)
對於證實相似於上列三元並集證實。
貼一題目(四元):
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<queue> #include<stack> #include<algorithm> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define Mem0(x) memset(x,0,sizeof(x)) #define Mem1(x) memset(x,-1,sizeof(x)) #define MemX(x) memset(x,0x3f,sizeof(x)) using namespace std; typedef long long ll; const int inf=0x3f3f3f; const double pi=acos(-1.0); ll l,r,k; ll prime[500050]; bool check[1000010]; int cnt; void prim() { memset(check,false,sizeof(check)); check[0]=check[1]=true; cnt=0; for (int i=2;i<500000;i++){ if (!check[i]) prime[cnt++]=i; for (int j=0;j<cnt&&i*prime[j]<1000000;j++){ check[i*prime[j]]=true; if (i%prime[j]==0) break; } } } ll a[1000010]; int main() { prim(); cin>>l>>r>>k; ll p=0;//質因數的個數 ll tmp=k<<1; /* for (int i=0;;i++){ if (tmp%prime[i]==0){ a[p++]=prime[i]; while (tmp%prime[i]==0){ tmp/=prime[i]; } } if (tmp<=1) break; }*/ for(int i=2;i*i<=tmp;i++){ if(!(tmp%i)){ a[p++]=i; while(!(tmp%i)) tmp/=i; } } if(tmp>1) a[p++]=tmp; ll sum=0; tmp=1<<p;// 存在p個質數,則有pow(2,p)種的組合數, for (int i=0;i<tmp;i++){ ll t=1,s=0; //t是質因數的公倍數,s則爲選舉的質因數的個數 for (int j=0;j<p;j++){ if (i&(1<<j)){ s++; t*=a[j]; } } if(r/t>(l+2*k-1)/t){ //容斥 奇加偶減 if(s%2)sum-=r/t-(l+2*k-1)/t; else sum+=r/t-(l+2*k-1)/t; } } cout<<sum<<endl; return 0; }