【POJ 2689】Prime Distance【数论,数学】

题目大意:

题目链接:http://poj.org/problem?id=2689
llrr之间相邻的差最小以及最大的质数。


思路:

这道题真的是烦。。。
这里写图片描述
这里写图片描述
MLE和RE了超级多次,最后发现是一个极其不起眼的东西。。。
这道题l,r231l,r\leq 2^{31},但是rl106r-l\leq 10^6,所以可以考虑从l,rl,r方面入手。
首先我们知道nn的质因子枚举到n\sqrt{n}就可以了,那我们可以先将不大于2312^{31}次方的质数用线性筛筛出来,时间复杂度O(r)O(\sqrt{r}),约为O(47000)O(47000)
然后对于每一组数据,我们先从枚举每个质数,再从llrr枚举,每次直接加prime[i]prime[i],然后被枚举到的数就绝对是合数。这里的理论时间复杂度是O((rl)r)O((r-l)\sqrt{r}),语约为O(47000000000)O(47000000000),完全会TT。但是这只是理论,实际来说,当r=231r=2^{31}时,所有枚举的质数约为50005000个,第二重循坏最多执行500000500000次,最少执行11次,平均约为1010次!(经程序输出)
那么这一段的时间复杂度就约为O(50000)O(50000),但是还是有一些卡时。
当然你还可以用gotogoto再简化。在POJ上评测加了gotogoto会少20ms20ms(当然并不建议用gotogoto)。
之后我们就求出了llrr之间的所有质数,那么接下来暴力枚举就可以啦!


代码:

#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;
}
posted @ 2018-08-24 20:43  全OI最菜  阅读(110)  评论(0编辑  收藏  举报