大意:区间找素数。
区间a and
b (1 ≤ a ≤ b < 231, b - a ≤ 100000).
分析:发现一个特点,a和b的数字都特别大,但是b-a倒是挺小的,从这里做文章。
找出1——1e6之间的素数,对a——b之间素数筛选,结果记录在一个长度是1e5的数组tag里,由此空间复杂度的问题解决了。另外筛选也是有技巧的,一个素数筛选应是人为设定筛选起点:max(a/prim[i]*prim[i],prim[i]*prim[i]),然后不断加上素数,淘汰非素数。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1e6+10;
typedef long long LL;
LL prim[N],cnt;
bool vis[N];
bool tag[N/10+10];
void getprim(){
for(LL i=2;i<N;i++){
if(!vis[i]) prim[cnt++]=i;
for(LL j=0;j<cnt&&i*prim[j]<N;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
}
}
}
int main(int argc, char *argv[]) {
//freopen("cin.txt","r",stdin);
getprim();
LL t,ca=1;
LL a,b;
scanf("%lld",&t);
while(t--){
memset(tag,0,sizeof(tag));
scanf("%lld%lld",&a,&b);
for(LL i=0;i<cnt&&prim[i]*prim[i]<=b;i++){ //prim[i]*prim[i] is the start point and care about int *int <0
LL s=max(a/prim[i]*prim[i],prim[i]*prim[i]);
for(LL j=s;j<=b;j+=prim[i]) if(j>=a) tag[j-a]=1;
}
LL len=b-a;
int ans=0;
for(int i=0;i<=len;i++){
if(tag[i]==0) ans++;
//printf("%d: %d\n",i+a,tag[i]);
}
if(a==1) ans--;
printf("Case %lld: %lld\n",ca++,ans);
}
return 0;
}