题目大意:
题目链接:http://poj.org/problem?id=2689
求到之间相邻的差最小以及最大的质数。
思路:
这道题真的是烦。。。
MLE和RE了超级多次,最后发现是一个极其不起眼的东西。。。
这道题,但是,所以可以考虑从方面入手。
首先我们知道的质因子枚举到就可以了,那我们可以先将不大于次方的质数用线性筛筛出来,时间复杂度,约为。
然后对于每一组数据,我们先从枚举每个质数,再从到枚举,每次直接加,然后被枚举到的数就绝对是合数。这里的理论时间复杂度是,语约为,完全会。但是这只是理论,实际来说,当时,所有枚举的质数约为个,第二重循坏最多执行次,最少执行次,平均约为次!(经程序输出)
那么这一段的时间复杂度就约为,但是还是有一些卡时。
当然你还可以用再简化。在POJ上评测加了会少(当然并不建议用)。
之后我们就求出了到之间的所有质数,那么接下来暴力枚举就可以啦!
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define ll long long
#define M 1000020
#define Inf 1e16
using namespace std;
ll l,r,m,sum,minn,maxn,prime[M],v[M],tail,max_r,max_l,min_r,min_l;
bool ok,p[M];
void find_prime(ll n) //离线求质数(线性筛)
{
for (ll i=2;i<=n;i++)
{
if (!v[i])
{
prime[++m]=i;
v[i]=i;
}
for (ll j=1;j<=m;j++)
{
if (prime[j]>v[i]||i*prime[j]>n) break;
v[i*prime[j]]=prime[j];
}
}
}
int main()
{
find_prime(50000);
while (~scanf("%lld%lld",&l,&r))
{
sum=r-l+1;
memset(p,0,sizeof(p));
if (l==1) //特判,1不是质数
{
p[1]=1;
sum--;
}
for (ll i=1;prime[i]<=sqrt(r);i++)
for (ll j=l+(prime[i]-(l%prime[i]))%prime[i];j<=r;j+=prime[i]) //直接求出第一个质数,然后就每次加prime[i]
{
if (sum<2) goto stop; //不建议使用
if (j<0||prime[i]==j) continue;
if (!p[j-l+1]) sum--;
p[j-l+1]=true;
}
stop:
if (sum<2)
{
printf("There are no adjacent primes.\n");
continue;
}
minn=Inf;
maxn=-Inf;
tail=-1;
for (ll i=l;i<=r;i++) //爆枚
if (!p[i-l+1])
{
if (tail>-1)
{
if (i-tail>maxn)
{
maxn=i-tail;
max_l=tail;
max_r=i;
}
if (i-tail<minn)
{
minn=i-tail;
min_l=tail;
min_r=i;
}
}
tail=i;
}
printf("%lld,",min_l);
printf("%lld are closest, ",min_r);
printf("%lld,",max_l);
printf("%lld are most distant.\n",max_r);
}
return 0;
}