LightOJ - 1197 大区间素数

给定整数a和b,请问区间[a,b)内有多少个素数?

a< b<=10^12

b-a<=10^6

输入 

22 37 
输出 

输入 
22801763489 2280178297 
输出 
1000

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

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
bool v[maxn],s[maxn];
int init(ll a,ll b)
{
    for(int i=0;(ll)i*i<=b;i++)
        v[i]=0;
    for(int i=0;i<=b-a;i++)
        s[i]=1;           
    //利用0~(a-b)代表a~b的数
    for(ll i=2;i*i<=b;i++)
        if(!v[i])
        {
            for(ll j=i+i;j*j<=b;j+=i)
                v[j]=1;              //筛[2,√b)
            for(ll j=max(2ll,(a+i-1)/i)*i;j<=b;j+=i)
                s[j-a]=0;             //筛[a,b)
            //j代表素数,j-a是将a~b变为0~b-a以便数组好存储
            //2LL是2的长整形形式,与其比较意思是j最少是i的两倍
            //((a+i-1)/i)*i得出的是(>=a && %i==0)离a最近的数,其实
            //也可以写成a%i==0 ? a : (a/i+1)*i
        }
    int cnt=0;
    for(int i=0;i<=b-a;i++)
        if(s[i])
            cnt++;
    return cnt;
}
int main()
{
    int t,h=1;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b;
        scanf("%lld%lld",&a,&b);
        int cnt=init(a,b);
        if(a==1)
            cnt--;
        printf("Case %d: %d\n",h++,cnt);

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41837216/article/details/82113692