题目链接:http://poj.org/problem?id=2689
题意:给出区间l,r(1<=l<r<=2147483647),要找到出相邻素数距离最小和距离最大各一对,如果有多对,输出最初的。
思路:解决这个题目首先需要将[l,r]范围的所有素数找出来,但是l,r范围太大,全找出来是不可能的。因为题目给出l和r的差不超过1000000,将sqrt(r)内的素数打个表, 再用 它去筛选 [l, r] 内的合数, 然后再遍历一次 [l, r], 记录答案即可,这样找素数时间复杂度为O(sqrt(r)),遍历时间复杂度为O(r-l),不会超时。
代码
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=50005; const int maxm=1e6+10; int prime1[maxn]; bool isprime[maxm]; int nprime1,nprime2; ll l,r,prime2[maxm]; void p1()//打表1~sqrt(r)里的素数 { nprime1=0; memset(isprime,1,sizeof(isprime)); for(ll i=2;i<maxn;i++) { if(isprime[i]) prime1[++nprime1]=i; for(int j=1;j<=nprime1;j++) { if(i*prime1[j]>maxn) break; isprime[i*prime1[j]]=0; if(i%prime1[j]==0) break; } } } void p2() { memset(isprime,1,sizeof(isprime)); for(ll i=1;i<=nprime1;i++) { ll sum=l/prime1[i]; while(sum*prime1[i]<l||sum<=1)//使sum*prime1[i]>=l且不是素数 sum++; for(ll j=sum*prime1[i];j<=r;j+=prime1[i]) { if(j>=l)//筛掉[l,r]中的合数 isprime[j-l]=0; } } if(l==1) isprime[0]=0; } void solve() { ll maxx=-inf,minx=inf; ll minl,minr,maxl,maxr; p2(); nprime2=0; for(int i=0;i<=r-l;i++)//遍历[l,r],保存其中的素数。 { if(isprime[i]) prime2[++nprime2]=i+l; } if(nprime2<=1) printf("There are no adjacent primes. "); else { for(int i=1;i<nprime2;i++) { if(prime2[i+1]-prime2[i]>maxx) { maxx=prime2[i+1]-prime2[i]; maxl=prime2[i],maxr=prime2[i+1]; } if(prime2[i+1]-prime2[i]<minx) { minx=prime2[i+1]-prime2[i]; minl=prime2[i],minr=prime2[i+1]; } } printf("%lld,%lld are closest, %lld,%lld are most distant. ",minl,minr,maxl,maxr); } } int main() { p1(); while(scanf("%lld%lld",&l,&r)!=EOF) { solve(); } return 0; }