M - Help Hanzo LightOJ - 1197 (大区间素数筛法)

题解:素数区间问题。注意到a和b的范围是1<<31,所以直接暴力打表肯定不可以。如果一个数是合数,他的两个因子要么是两个sqrt(x),要么就分布在sqrt(x)两端,所以我们可以根据sqrt(n)之前的数来把sqrt(n)之后的素数给筛出来。

首先进行1e6的素数打表。然后对每个l,r,首先找到第一个大于等于l的数,然后根据刚才的筛出来素数,一直累加,直到r为止,这样就可以把因子在1e6范围的合数给标记上了。注意我们保存的时候数组中要减去l,这样数组只要开到1e5就可以了。注意当l=1时,1不是素数,要特判一下。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1E6+7;
bool primes[N];
ll  pre[N];
ll pos=0;
ll mp[100000+7];
void inint(){
    ll maxxn=1e6;
    primes[1]=1;
    primes[2]=0;
    for(ll i=2;i<=maxxn;i++){
        if(!primes[i]) pre[++pos]=i;
        for(ll j=1;j<=pos&&i*pre[j]<=maxxn;j++){
            primes[i*pre[j]]=1;
            if(i%pre[j]==0) break;
        }
    }
}
int main(){
    inint();   
    ll t;
    cin>>t;
    int time=0;
    while(t--){
        memset(mp,0,sizeof mp);
        int l,r;
        cin>>l>>r;
        for(ll i=1;i<=pos;i++){
            ll c=l/pre[i];
            if(l%pre[i]!=0) c++;
            for(ll j=c*pre[i];j<=r;j+=pre[i]){
                if(j==pre[i]) continue ;
                mp[j-l]=1;
            }
        }
        ll ans=0;
        for(ll i=l;i<=r;i++){
            if(!mp[i-l]) ans++;
        }
        if(l==1) ans--;
        printf("Case %d: %lld\n",++time,ans);
    }
    return 0;
}

 

上一篇:显示与隐式类型转换


下一篇:【Luogu】 P6303 [eJOI2018]AB 串 题解