给定a,b求[a,b)区间内的素数数量(1 ≤ a ≤ b < 231, b - a ≤ 100000)
暴力线性筛mle,这时就要用到区间线性筛了,利用数组偏移,只需要筛一下(1,sqrt(b))
#include <iostream>
#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;
//对区间[a,b)内的整数执行筛法,is_prime[i-a]=true --- 表示i是素数 注意这里下标偏移了a,所以从0开始。
void segment_sieve(ll a,ll b)
{
for(ll i=0;i*i<b;++i)
{
is_prime_small[i]=true;//对[2,sqrt(b))的初始化全为质数
}
for(ll i=0;i<b-a;++i)
{
is_prime[i]=true;//对下标偏移后的[a,b)进行初始化
}
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;//筛选[2,sqrt(b));
}
//(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选,两者取max
for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i)
{
is_prime[j-a]=false;//j必须从大于1,因为a可能小于i,但是is_prime[i]是素数
}
}
}
for(ll i=0;i<b-a;++i) //统计个数
{
if (is_prime[i])
{
prime[prime_num++] = i + a;
}
}
}
int main()
{
int k;
cin>>k;
for(int cas=1;cas<=k;cas++)
{
ll a,b;
cin>>a>>b;
cout<<"Case "<<cas<<": ";
prime_num=0;
memset(prime,0,sizeof(prime));
segment_sieve(a,b+1);
if(a==1)
{
prime_num--;
}
cout<<prime_num<<endl;
}
return 0;
}