质数距离--------------------------------------数论(线性筛+区间映射)

给定两个整数L和U,你需要在闭区间[L,U]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。

同时,你还需要找到距离最远的两个相邻质数D1和D2(即D1-D2是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。

输入格式
每行输入两个整数L和U,其中L和U的差值不会超过1000000。

输出格式
对于每个L和U ,输出一个结果,结果占一行。

结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)

如果L和U之间不存在质数对,则输出“There are no adjacent primes.”。

数据范围
1≤L 输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

解析:
不能暴力筛,因为n=2e9多的范围,肯定会超时。
假设一个合数x
一个因数 n 另一个 x/n
那么因数n一定小于 x/n
根据这个性质我们可以把[L,R]内的合数开根号筛出来。
2e9开根号大约50000

n=50000 我们跑线性筛。找出[1.50000]中的所有质因子。那么一个合数分解肯在有一部分在[1.50000]。

对于[1,50000]中每个质数p,将[L,R]中所有为p的倍数筛掉(至少为2倍)

那么大于等于L的最小的p的倍数 p0=(L+p-1)/p * p;
因为至少要是2倍 p0=max(2*p,(L+p-1)/p * p);

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+1000;
int prime[N],cnt;
bool st[N];
ll l,r;
void init(int n)
{
	memset(st,false,sizeof st);
	cnt=0;
	for(int i=2;i<=n;i++)
	{
		if(!st[i]) prime[++cnt]=i;
		for(int j=1;j<=cnt&&prime[j]<=n/i;j++)
		{
			st[prime[j]*i]=true;
			if(i%prime[j]==0) break;
		}
	}
}
int main()
{
	while(~scanf("%lld %lld",&l,&r))
	{
		init(50000);
		memset(st,false,sizeof st);
		for(int i=1;i<=cnt;i++)
		{
			ll p=prime[i];
			for(ll j=max(p*2,(l+p-1)/p*p);j<=r;j+=p) st[j-l]=true;
			
		}
		cnt=0;
		for(int i=0;i<=r-l;i++)
		{
			if(!st[i]&&(i+l)>=2) //1不是质数,所以必须从2开始
			{
				prime[++cnt]=i+l;
			}
		}
		if(cnt<2) puts("There are no adjacent primes.");
		else
		{
			int minp=1,maxp=1;
			for(int i=1;i<=cnt-1;i++)
			{
				int d=prime[i+1]-prime[i];
				if(d<prime[minp+1]-prime[minp]) minp=i;
				if(d>prime[maxp+1]-prime[maxp]) maxp=i;
			}
			printf("%d,%d are closest, %d,%d are most distant.\n",prime[minp],prime[minp+1],prime[maxp],prime[maxp+1]);
		}
	}
}

你可能感兴趣的:(数论)