容斥原理的二進制實現模版

最近學習容斥原理,實現容斥原理大體有三種方法:dfs,隊列數組,二進制。ios

今天主要講下二進制實現容斥原理:數組

   有一個集合{A1……An},求集合的子集?很顯然答案爲學習

也就是2^n個,也就是每個子集有惟一標誌符 i (0<i<2^n,空集除外),也就是說有惟一的二進制表示!spa

代碼看下面的:3d

 1 #include<iostream>  2 #include<stdio.h>  3 #include<algorithm>  4 #include<iomanip>  5 #include<cmath>  6 #include<cstring>  7 #include<vector>  8 #include<stdlib.h>  9 using namespace std; 10 int prime[40000],m; 11 bool f[40000]; 12 vector<int>p;//存放質因數 13 //用篩法初始化40000之內的質數,將質數存放在prime數組中,m記錄大小 14 int init(){ 15 m=0; 16 for(int i=2; i<40000; i++){ 17 if (f[i]==0) prime[m++]=i;//質數 18 //篩去合數 19 for (int j=0; j<m&&i*prime[j]<40000; j++){ 20 f[i*prime[j]]=1; 21 if (i%prime[j]==0) break;//保證每一個數只篩去一次 22  } 23  } 24 } 25 //對n分解質因數 26 void factor(int n){ 27  p.clear(); 28 for (int i=0; i<m&&prime[i]*prime[i]<=n; i++){ 29 if (n%prime[i]==0){ 30  p.push_back(prime[i]); 31 n/=prime[i]; 32 while (n%prime[i]==0) 33 n/=prime[i]; 34  } 35  } 36 if(n>1) p.push_back(n); 37 } 38 //用二進制實現容斥原理,求區間[1,r]內與n互素的數的個數 39 int solve(int r){ 40 int sum = 0; 41 //i的範圍是1-2^p.size(),空集除外,每個子集所對應的 42 //二進制都不同,也就是i 43 for (int i=1; i<(1<<p.size()); ++i){ 44 int mult = 1,bits = 0; 45 for (int j=0; j<p.size(); ++j) 46 if (i&(1<<j)){//與i的二進制的第j位比較,看是否爲1,是則選中 47 bits++;//計算i中1的個數,也就是質因數的個數 48 mult *= p[j]; 49  } 50 int cur = r / mult; 51 if (bits & 1)//若1的個數是奇數則進行加法,不然進行減法 52 sum += cur; 53 else sum -= cur; 54  } 55 return r - sum;//用總的數目-與n不互素的個數 56 } 57 int main(){ 58  init(); 59 int n,r; 60 while(cin>>n>>r){ 61  factor(n); 62 cout<<solve(r)<<endl; 63  } 64 return 0; 65 }
相關文章
相關標籤/搜索