题意:给定两个数l,r求这之间最近和最远的两个素数。数据范围是整数的上限。r-l<=10^6
分析:总思路是把l和r间的素数全部找出来,然后遍历一遍求最小距离和最大距离。用一个函数预处理数据范围内的所有素数是不现实的,一来数组不可r能开那么大二来会超时。想想素数筛的思想:用sqrt(n)以内的素数筛掉n以内的所有合数,剩下n以内的素数。这里既然预处理不可能,我们一样可以用sqrt(n)以内的素数来筛,只是这时这些素数预处理,然后每次输入l和r的时候用预处理的素数筛掉l和r之间的合数,剩下素数。sqrt(n)为2^16,也就是65536不会超时。
关键在于l,r之间的素数筛。还是用vis[]数组来做。直接用两个循环遍历 l~r 和 prim[] 估算一下应该是会超时的,所以用到一点优化技巧就是遍历l~r的时候每次加prim[i],而不是加1
代码:
#include<iostream>
#include<cstring>
using namespace std;
long long l,r,vis[5000003],l1,l2,r1,r2,init;
int prim[500005],mi,mx,cnt;
void is_prim()
{
memset(vis,1,sizeof(vis));
cnt=0;
for(int i=2;i<=50000;i++){
if(vis[i]){
prim[cnt++]=i;
for(int j=2;j*i<=50000;j++) vis[j*i]=0;
}
}
}
int main()
{
is_prim();
while(cin>>l>>r){
for(int i=0;i<r-l+1;i++) vis[i]=1;
if(l==1) vis[0]=0;
for(int i=0;i<cnt&&prim[i]*prim[i]<=r;i++){
for(long long j=(long long)max((long long)(prim[i]<<1),(l+prim[i]-1)/prim[i]*prim[i]);j<=r;j+=prim[i])
vis[j-l]=0;
}
init=-1;
mx=-1,mi=10000000;
for(int i=0;i<r-l+1;i++){
if(vis[i]){
if(init!=-1){
if(mi>i-init){
mi=i-init;
l1=init+l;
r1=i+l;
}
if(mx<i-init){
mx=i-init;
l2=init+l;
r2=i+l;
}
}
init=i;
}
}
if(mx==-1) cout<<"There are no adjacent primes."<<endl;
else cout<<l1<<","<<r1<<" are closest, "<<l2<<","<<r2<<" are most distant."<<endl;
}
}