题目链接:http://poj.org/problem?id=2689
左右区间位于int大范围内但是区间长度只有1e6,所以可以考虑先筛出根号R内的质数之后用这些质数去筛(L,R)区间的质数,筛的时候注意至少要从2*p开始,因为p为质数
在(L,R)区间内第一个p的倍数和最后一个p的倍数分别是(L/p)上取整*p 和 R/p下取整*p.
另外一个注意点就是,如果左边界是1的话,要筛掉1,因为1不是质数也不是合数,并且不会被使用的质数筛掉。
需要预处理出根号R下取整范围内的质数
代码
#include<iostream> #include<cstring> #include<vector> using namespace std; #define maxn 1000010 typedef long long ll; #define M 46340 bool v[maxn]; const int inf=0x7fffffff; vector<int> p ,ans; int main(){ memset(v,1,sizeof(v));//用0x01对每一个字节进行赋值 for(int i=2;i<=M;i++) if(v[i]){//没有被筛掉 p.push_back(i); for(int j=2;j<=M/i;j++)v[i*j]=0;//筛掉i的倍数 } ll l,r; while(cin>>l>>r){ memset(v,1,sizeof(v)); ans.clear(); if(l==1)v[0]=0;//1除去,不是合数也不是质数 for(ll i=0;i<p.size();i++) //最小的j=l/p[i]上取整,最大的j=r/p[i]下取整,保证 for(ll j=max((l+p[i]-1)/p[i],2ll);j<=r/p[i];j++){ v[j*p[i]-l]=0;//计算偏移,将能被整除的数筛掉 } for(ll i=l;i<=r;i++){ if(v[i-l])ans.push_back(i); } int minn=inf,maxx=0,x,y; for(int i=0;i+1<ans.size();i++){ int num=ans[i+1]-ans[i]; if(num>maxx){ maxx=num; x=i; } if(num<minn){ minn=num; y=i; } } if(minn==inf)puts("There are no adjacent primes."); else printf("%d,%d are closest, %d,%d are most distant. ", ans[y],ans[y+1],ans[x],ans[x+1]); } }