题解:素数区间问题。注意到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
",++time,ans);
}
return 0;
}