容斥原理(三元容斥,四元容斥)

 

 

 

題意:    已知集合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    規律   集合數    奇加偶減

 

對於證實相似於上列三元並集證實。   

 

貼一題目(四元):

  

 
 
給出一個數N,求1至N中,有多少個數不是2 3 5 7的倍數。 例如N = 10,只有1不是2 3 5 7的倍數。 輸入 輸入1個數N(1 <= N <= 10^18)。 輸出 輸出不是2 3 5 7的倍數的數共有多少。 輸入樣例 10 輸出樣例 1

 

AC代碼:

#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 n; int main() { ll ans=0; cin>>n; ans=n/2+n/3+n/5+n/7; ans=ans-n/6-n/10-n/14-n/15-n/21-n/35+n/30+n/42+n/105+n/70-n/210; cout<<n-ans<<endl; return 0; }

 

再貼一題:  (提供連接,就不貼題目了)

https://ac.nowcoder.com/acm/contest/634/C    

 
 
 
解題:
 
  

 

#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; }
相關文章
相關標籤/搜索