例题POJ2689添加链接描述
我们通过要求得一个区间[L,R]内的素数,由于L和R的数值可能会很大,如果用传统的线性筛来求解的话,会导致的问题。为了能够解决这个矛盾,我们利用效率低一点的埃氏筛来完成该题。
埃式筛的基本原理是,对于数n,必然存在2~√n之间的质数p是n的因数,所以这些质数的倍数k*p必然是合数。所以我们需要枚举筛完这个区间所需要的质数,然后枚举它的倍数然后筛去以它为因数的合数,对于该题,我们只需要筛出50000以内的质数就够了,这一步可以借用前面的线性筛来完成。
由于,如果令一个整数为k=(L-1)/p,那么k*p就是小于L的最大p的最大倍数,那么(k+1)*p就是大于等于L的第一个合数。注意,由于我们是筛的合数,故作为起始点,k+1必然是大于等于2的,否则如果k=0,p就是一个质数,就会出现错误。所以,为了保证如果p>=L,k=0时不出错,最终的起始系数x=max(2,k+1)。
我们从x开始枚举,(x+1)*p,(x+2)*p…依次标记为合数,将所有可能的p都用来筛一遍,最终留下来的就是质数了。根据本题的题意,再将合题的质数选出来即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define maxn 1000005
using namespace std;
typedef pair<long long,long long> P;
int check[maxn];
int prime[maxn];
int v[maxn];
int tot=0;
int fin() //线性筛先得出所有用来筛选的质数
{
for(int i=2;i<=50000;i++)
{
if(!check[i])
{
prime[tot]=i;
tot++;
}
for(int j=0;j<tot&&prime[j]*i<=50000;j++)
{
check[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
pair<P,P> solve(long long L,long long R)
{
memset(v,0,sizeof(v));
for(int i=0;i<tot;i++)
{
for(long long j=max(2ll,(L-1)/prime[i]+1)*prime[i];j<=R;j+=prime[i])//埃氏筛筛选素数
{
v[j-L]=1;
}
}
long long a=-1,b=-1,x=-1,y=-1,z=-1,d=maxn,f=-1;
for(long long i=L;i<=R;i++)
{
if(v[i-L])continue;
if(z==-1){z=i;continue;}
if(i-z<d)
{
x=z;
y=i;
d=i-z;
}
if(i-z>f)
{
a=z;
b=i;
f=i-z;
}
z=i;
}
if(a==-1||b==-1||a==b)return make_pair(make_pair(-1,-1),make_pair(-1,-1));
else return make_pair(make_pair(a,b),make_pair(x,y));
}
int main()
{
long long L,R;
fin();
while(cin>>L>>R)
{
int u=0;
if(R<2)u=1;
L=max(2ll,L);
pair<P,P>ans=solve(L,R);
if(!u&&ans.first.first==-1)
{
cout<<"There are no adjacent primes."<<endl;
}
else
{
cout<<ans.second.first<<","<<ans.second.second<<" are closest, "<<ans.first.first<<","<<ans.first.second<<" are most distant."<<endl;
}
}
}