题目大意
给定左右区间,求出区间内两个相邻质数中相差最大和最小的两队, 没有就输出
There are no adjacent primes.
范围
1 ≤ L < R ≤ 2^31−1
样例
输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
思路
这里采用的是素数线性筛选, 但是因为数据范围不大,用朴素筛选也行, 具体的素数筛选讲解可以查看 ==>> 这篇博客
L,R的范围很大,任何已知算法都无法在规定时间内生成[1,R] 中的所有质数。但是R-L的值很小,并且任何一个合数n必定包含一个不超过 √n的质因子。(关键)
所以,我们只需要用筛法求出2 ~ sqrt( R )之间的所有质数。对于每个质数p,把[L,R]中能被p整除的数标记,即标记i * p( l / p ≤ i ≤ r / p)(上取整)为合数。
最终所有未被标记的数就是[L, R]中的质数。对相邻的质数两两比较,找出差最大的即可。
在存L 到 R 之间的素数时, 只需要存 P - L 就行了, 因为不能开那么大的空间, R - L 不大于1e6 所以开 1e6 + 10 的空间就够了
for(int i = 1; i <= m; i++){
int p = prime[i];
for (long long j = max((l + p - 1) / p * p, 2ll * p); j <= r; j += p)
vis[j - l] = true; //这里是j - l 不是存的j
}
然后这里还原
for(int i = 0; i <= r - l ; i++)
if(!vis[i] && i + l > 1 )
prime[++m] = i + l;
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1000010;
int prime[N];
bool vis[N];
int m;
void get_primes(int n){
memset(vis, false, sizeof vis);
m = 0;
for(int i = 2; i <= n; i++){
if(!vis[i]) prime[++m] = i;
for(int j = 1; prime[j] * i <= n; j++){
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
}
}
}
int main(){
ll l, r;
while(~scanf("%lld%lld", &l, &r)){
get_primes(50000);
memset(vis, false, sizeof vis);
for(int i = 1; i <= m; i++){
int p = prime[i];
for (long long j = max((l + p - 1) / p * p, 2ll * p); j <= r; j += p)
vis[j - l] = true;
}
m = 0;
for(int i = 0; i <= r - l ; i++)
if(!vis[i] && i + l > 1 )
prime[++m] = i + l;
if(m < 2) cout << "There are no adjacent primes." << endl;
else{
int minn = 1, maxx = 1;
for(int i = 1; i <= m - 1; i++){
int dis = prime[i + 1] - prime[i];
if(dis < prime[minn + 1] - prime[minn]) minn = i;
if(dis > prime[maxx + 1] - prime[maxx]) maxx = i;
} printf("%d,%d are closest, %d,%d are most distant.\n", prime[minn], prime[minn + 1], prime[maxx], prime[maxx + 1]);
}
}
return 0;
}