区间筛法

区间[a,b)指的是所有满足a<=x<b的整数(跟据背景也可能是实数)所构成的集合。

b以内的合数的最小质因数一定不超过根号b。如果有根号b以内的素数表的话,就可以把挨式筛选法运用到[a,b)上了,也就是说,先分别做好[2,根号b)的表和[a,b)的表,然后从[2,根号b)的表中筛得素数得同时,也将其倍数从[a,b)的表中划去,最后剩下的就是[a,b)的素数了。

#include<iostream> 
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int maxn = 1000005;

bool is_prime[maxn];//下标偏移 
bool is_prime_small[maxn];
ll prime[maxn];
ll prime_num=0;

void segment_sieve(ll a,ll b) {
    for(ll i=0;i*i<b;++i) is_prime_small[i]=true;//0~sqrt(b) 
    for(ll i=0;i<b-a;++i) is_prime[i]=true;//a~b->0~b-a

    for(ll i=2;i*i<b;++i) {
        if(is_prime_small[i]) {
            for(ll j=2*i;j*j<b;j+=i) is_prime_small[j]=false;
            //2LL是2的长整型形式
			//((a+i-1)/i)*i)是满足>=a&&%i==0的离a最近的数
			//也可以写成(a%i==0)?a:(a/i+1)*i
            for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i) is_prime[j-a]=false;
        }
    }
    for(ll i=0;i<b-a;++i) 
        if(is_prime[i]) prime[prime_num++]=i+a;
}	

int main()
{
    ll a,b;
    while(~scanf("%lld%lld",&a,&b))
    {
        prime_num=0;
        memset(prime,0,sizeof(prime));
        
        segment_sieve(a,b);
        
        for(ll i=0;i<prime_num;++i) printf("%lld\n",prime[i]);
        printf("%lld\n",prime_num);
    }
    return 0;
}

阅读更多

没有更多推荐了,返回首页