题解:素数区间问题。注意到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; }