区间[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;
}