大区间素数查找。
因为给出的数据范围太大,无法开到那么大的数组,所以不可以一开始预处理出所有的素数。
又因为l和u之间的差值最大1e6,所以也不可能一个一个地去判断。
正确的方法时,先预处理出 sqrt(N)范围内的全部素数,那么就可以通过这些素数来判断1~N内的所有数是素数还是合数。
对于给定的区间[l,u],利用埃氏筛的思想,选择相应的素数,把给定区间的素数的倍数给去除。又考虑到数据范围,可以把l[l,u]内的数全部都减小l来存入标记。
最后只要统计一下,剩下的素数的个数,并找到目标解,即可。
一个注意的地方就是,利用埃氏筛的思想进行筛选时,用累加。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const ll N=2147483650;
const ll inf=0x3f3f3f3f;
const int MAXN=1e6+5;
const int M=46350;
bool vis[M];
bool book[MAXN];
vector<int>prime;
ll l,u;
void oula()
{
memset(vis,false,sizeof(vis));
prime.clear();
for(int i=2;i<M;i++)
{
if(!vis[i])
prime.push_back(i);
for(int j=0;j<prime.size()&&i*prime[j]<M;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0)
break;
}
}
}
void solve()
{
for(ll i=0;i<=u-l;i++)
book[i]=true;
for(int i=0;i<prime.size()&&prime[i]<=u;i++)
{
ll num=l/(ll)prime[i];
ll w=num*prime[i];
while(w<l||w==prime[i])
w+=prime[i];
for(ll j=w;j<=u;j+=prime[i])//用加法,不用用乘法,否则超时
{
if(j>=l)
book[j-l]=false;
}
}
}
int main()
{
oula();
while(scanf("%lld%lld",&l,&u)!=EOF)
{
int cnt=0;
ll a=0,b=0,c=0,d=0,minn=inf,maxn=0,t=0;
solve();
for(int i=0;i<=u-l;i++)
{
if(book[i]&&i+l>1)
{
cnt++;
if(cnt>=2)
{
if(i+l-t<minn)
{
a=t;
b=i+l;
minn=i+l-t;
}
if(i+l-t>maxn)
{
c=t;
d=i+l;
maxn=i+l-t;
}
}
t=i+l;
}
}
if(cnt<2)
printf("There are no adjacent primes.\n");
else
printf("%lld,%lld are closest, %lld,%lld are most distant.\n",a,b,c,d);
}
return 0;
}