首先数据范围太大,一开始我想的是,用欧拉筛处理出1~sqrt(1<<31-1)内的素数,然后枚举[a,b]内的所有数,用预处理的素数进行判断。但一直t。
正解:
根据b-a<=1e5,所以可以对a和b的不同取值进行分类。
先用欧拉筛处理出1e5以内的所有的素数,用vis1数组标记。
当a<=1e5&&b<=1e5时:直接枚举计数即可。
此外,用另一个数组标记,但由于数值较大,不能开那么大的数组,所以就可以把所有的数-a,使得所有的数据变小。
然后利用之前处理的素数,来判断区间[a,b]的数是否为素数(埃氏筛的思想),标记。然后遍历计数。

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
bool vis1[N],vis2[N];
int prime[80000],cnt;
typedef long long ll;
void euler()
{
    memset(vis1,0,sizeof(vis1));
    cnt=0;
    vis1[1]=1;
    for(int i=2;i<=N-5;i++)
    {
        if(!vis1[i])
            prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=N-5;j++)
        {
            vis1[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
}
int main()
{
    int t,cas=0;
    euler();//cout<<cnt<<endl;
    scanf("%d",&t);
    ll a,b;
    while(t--)
    {
        scanf("%lld%lld",&a,&b);
        int ans=0;
        if(a<=N-5&&b<=N-5)
        {
            for(ll i=a;i<=b;i++)
                if(!vis1[i])
                    ans++;
        }
        else
        {
            memset(vis2,0,sizeof(vis2));
            for(int i=1;i<=cnt&&prime[i]*prime[i]<=b;i++)
            {
                for(ll j=a/prime[i]*prime[i];j<=b;j+=prime[i])
                {
                    if(j>=a&&!vis2[j-a])
                        vis2[j-a]=1;
                }
            }
            for(int i=0;i<=b-a;i++)
                if(!vis2[i])
                    ans++;
        }
        printf("Case %d: %d\n",++cas,ans);
    }
    return 0;
}