大数区间素数筛

给定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;
}

猜你喜欢

转载自blog.csdn.net/neuq_zsmj/article/details/80356926
今日推荐