-
埃式篩法:給定一個正整數n(n<=10^6),問n以內有多少個素數?
做法:做法其實很簡單,首先將2到n范圍內的整數寫下來,其中2是最小的素數。將表中所有的2的倍數划去,表中剩下的最小的數字就是3,他不能被更小的數整除,所以3是素數。再將表中所有的3的倍數划去……以此類推,如果表中剩余的最小的數是m,那么m就是素數。然后將表中所有m的倍數划去,像這樣反復操作,就能依次枚舉n以內的素數,這樣的時間復雜度是O(nloglogn)。
題解:如果要是按照一個一個判斷是否是素數然后把ans+1,時間復雜度為O(n√n),對於10^6的數據時間復雜度就是O(10^9),必定會超時,但此時埃氏篩法的時間復雜度只有O(nloglogn)。
int prime[MAXN];//第i個素數 bool is_pri[MAXN+10];//is_pri[i]表示i是素數 //返回n以內素數的個數 int sieve(int n){ int p=0; for(int i=0;i<=n;i++)is_pri[i]=true; is_pri[0]=is_pri[1]=false; for(int i=2;i<=n;i++){ if(is_pri[i]){ prime[++p]=i; for(int j=2*i;j<=n;j+=i)is_pri[j]=false; } } return p; }
-
區間素數篩:給定兩個正整數a、b(a<b<=10^12、b-a<=10^6),請問[a,b)內有多少個素數?
主要思想:既然在之前已經講過b以內的和書的最小質因數不會超過√b。如果有√b以內的素數表的話,就可以把埃氏篩法運用在上面了。也就是說,我們可以先分別做好[2,√b)的表和[a,b)然后在第一個表的是素數的前提下,刪去第二個表中的數即可。
#include<iostream> using namespace std; bool pri[1000000+10]; bool ispri[10000000+10];//ispri[i-a]=true代表i是素數 void getpri(){ memset(pri,true,sizeof(pri)); pri[0]=pri[1]=0; for(int i=2;i<=1000000;i++){ if(pri[i]){ for(int j=2*i;j<=1000000;j+=i)pri[j]=0; } } } int main(){ long long a,b; scanf("%lld%lld",&a,&b); getpri(); memset(ispri,true,sizeof(ispri)); for(long long i=2;i*i<b;i++){ if(pri[i]){ for(long long j=max((a+i-1)/i,2LL)*i;j<b;j+=i) ispri[j-a]=0; } } long long cnt=0; for(int i=0;i<b-a;i++)if(ispri[i])cnt++; if(a==1)cnt--; printf("%lld\n",cnt); }