區間素數篩法


 

給定整數a和b,請問區間[a,b)內有多少個素數? 

a<b<=10^12

b-a<=10^6

因為b以內合數的最小質因數一定不超過sqrt(b),如果有sqrt(b)以內的素數表的話,就可以把篩選法用在[a,b)上了,先分別做好[2,sqrt(b))的表和[a,b)的表,然后從[2,sqrt(b))的表中篩得素數的同時,也將其倍數從[a,b)的表中划去,最后剩下的就是區間[a,b)內的素數了。

有的時候需要求出某個特定區間的素數,但是數可能很大,數組也開不小,所以需要進行下標偏移,這樣才可以使用篩選法。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn = 1000005;
 7 bool is_prime[maxn];
 8 bool is_prime_small[maxn];
 9 ll prime[maxn];
10 ll prime_num=0;
11 
12 //對區間[a,b)內的整數執行篩法,is_prime[i-a]=true  ---  表示i是素數 注意這里下標偏移了a,所以從0開始。
13 void segment_sieve(ll a,ll b) {
14     for(ll i=0;i*i<b;++i) is_prime_small[i]=true; //對[2,sqrt(b))的初始化全為質數
15     for(ll i=0;i<b-a;++i) is_prime[i]=true; //對下標偏移后的[a,b)進行初始化
16 
17     for(ll i=2;i*i<b;++i) {
18         if(is_prime_small[i]) {
19             for(ll j=2*i;j*j<b;j+=i) is_prime_small[j]=false;  //篩選[2,sqrt(b));
20             //(a+i-1)/i得到最接近a的i的倍數,最低是i的2倍,然后篩選
21             for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i) is_prime[j-a]=false;
22         }
23     }
24     for(ll i=0;i<b-a;++i)  //統計個數
25         if(is_prime[i]) prime[prime_num++]=i+a;
26 }
27 
28 int main()
29 {
30     ll a,b;
31     while(~scanf("%lld%lld",&a,&b))
32     {
33         prime_num=0;
34         memset(prime,0,sizeof(prime));
35         segment_sieve(a,b);
36         //for(ll i=0;i<prime_num;++i) printf("%lld\n",prime[i]);
37         printf("%lld\n",prime_num);
38     }
39     return 0;
40 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM