Prime Distance
被称为数论的数学分支是关于数的性质的。数理论家几千年来一直感兴趣的领域之一是素数问题。素数是一个没有适当因子的数(它只能被1和它本身整除)。第一个素数是2,3,5,7,但是它们很快就变得不那么频繁了。其中一个有趣的问题是它们在不同的范围内有多密集。相邻素数是两个都是素数的数,但相邻素数之间没有其他素数。例如,2,3是唯一的相邻素数也是相邻的数。 你的程序有两个数字:L和U(1<=L < U<=2147483647),你要找到最接近的两个相邻素数C1和C2(L<=C1 < C2<=U)(即C2-C1是最小值)。如果有其他线对相距相同,则使用第一对线对。你还可以找到两个相邻的素数D1和D2(L<=D1 < D2<=U),其中D1和D2尽可能地彼此远离(如果有并列关系,再次选择第一对)。
Input
每行输入将包含两个正整数L和U,其中L < U。L和U之间的差值不超过1000000。
Output
对于每个L和U,输出要么是不存在相邻素数的语句(因为两个给定数字之间的素数少于两个),要么是给出两对相邻素数的行。
Sample Input
2 17
14 17
Sample Output
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
这个题大意就是说给一个区间,然后求出在这个区间内相邻质数距离最大和最小的那两对质数,另外要注意在题目中给出的范围(1<=L < U<=2147483647),2e9的范围,如果用线性筛的话时间空间都会超限,题目中还说了L和U之间的差值不超过1000000,所以说咱们要是暴力求的话很大一部分求出的素数是没用的,但是筛素数又一定是从头开始的,那咱们就可以想到一个性质了,
具体代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1000010;
typedef long long LL;
int prime[N],cnt;
bool st[N];
void init(int n){//线性筛板子
memset(st,0,sizeof st);
cnt = 0;
for(int i=2;i<n;i++){
if(!st[i]) prime[cnt++] = i;
for(int j=0;prime[j]*i<n;j++){
st[i*prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
}
int main(){
int l,r;
while(cin>>l>>r){
init(50000);//注意这个50000,因为50000^2比2^31-1大
if(l == 1) l = 2;//因为l=1和l=2一样,所以我就感觉这样写的话会少一些麻烦
if(r == 1) r = 2;
memset(st,0,sizeof st);
for(int i=0;i<cnt;i++){
LL p = prime[i];//这个地方要开LL,因为如果p是int,j也是int,当j很大的时候他可能会爆int,因为这个j可能取到int的极限
for(LL j=max(p*2,(l+p-1)/p*p);j<=r;j+=p){//注意这个max,他至少是从p的两倍开始筛的,还有这个(l+p-1)/p*p,他的原型是[l/p]*p,
//就是从大于等于l的第一个p的倍数开始筛,有个公式可以推到代码所展现出来的,就是上取整和下取整之间的关系
st[j-l] = true;//因为数组没有那么大,所以相当于一个离散化
}
}
cnt = 0;
for(int i=0;i<=r-l && i+l>=2;i++)
if(!st[i]) prime[cnt++] = i+l;
int minn = 0,maxn = 0;
for(int i=0;i+1<cnt;i++){
int d = prime[i+1] - prime[i];
if(d < prime[minn+1] - prime[minn]) minn = i;
if(d > prime[maxn+1] - prime[maxn]) maxn = i;
}
if(cnt<2) puts("There are no adjacent primes.");
else printf("%d,%d are closest, %d,%d are most distant.\n",prime[minn],prime[minn+1],prime[maxn],prime[maxn+1]);
}
return 0;
}