给定两个整数 LL 和 UU,你需要在闭区间 [L,U][L,U] 内找到距离最接近的两个相邻质数 C1C1 和 C2C2(即 C2−C1C2−C1 是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。
同时,你还需要找到距离最远的两个相邻质数 D1D1 和 D2D2(即 D1−D2D1−D2 是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。
输入格式
每行输入两个整数 LL 和 UU,其中 LL 和 UU 的差值不会超过 106106。
输出格式
对于每个 LL 和 UU,输出一个结果,结果占一行。
结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)
如果 LL 和 UU 之间不存在质数对,则输出 There are no adjacent primes.
。
数据范围
1≤L<U≤231−11≤L<U≤231−1
输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
题意分析:
找到给定区间所有相邻素数的最近距离和最远距离
解题思路:
- 因为题目所给数据量太大,利用线性筛法也不能将所给的素数全部晒出来,所以利用 每一个合数都是一个素数的若干倍数
- 首先找到50000内的所有素数(朴素筛法就可以完成)
- 枚举每一个素数,所枚举素数的任何倍数都应该从所给区间里面去除
令枚举素数为p,首先要找到p的开始位置,p有可能在所给区间内,也有可能在所给区间外,这时候就需要找到一个开始的 p
这里用到一个公式:(l + r -1)/ p * p 就可以轻松得到这个 p
将所有倍数标记去除 - 找到区间内相距最近或者最远的素数
有可能没有素数
输出没有
有素数
利用两个标记 minp maxp
如果前一个素数与后一个素数(primes[i + 1] - primes[i])的距离小于 primes[minp + 1] - primes[minp] ,就将minp = i;
如果(primes[i + 1] - primes[i])的距离大于 primes[maxp + 1] - primes[maxp], 将maxp = i; - 最后按格式输出
易错分析:
- 在找起点p时
有可能p在题目给定的区间,因而我们不能直接将p筛掉,因该让起点为2 * p
因为给定的范围太大,所有应该用long long 定义 - 将所有质数存起来时
要判定 1 既不是素数也不是合数
另外储存的是 i + l 而不是 i
实现代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#define ll long long
const int N = 1e6;
int cnt;
int primes[N];
bool st[N];
// 线性筛法
void GetPrimes(int n)
{
memset(st, false, sizeof st);
cnt = 0;
for(int i = 2; i <= n; i ++)
{
if(!st[i])
primes[cnt++] = i;
for(int j = 0; primes[j] <= n / i; j ++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
int main()
{
ll l, r;
while(cin >> l >> r)
{
GetPrimes(50000);
// for(int i = 0; i < cnt; i ++)
// cout << primes[i] << endl;
memset(st, false, sizeof st);
for(int i = 0; i < cnt; i ++)
{
int p = primes[i];
for(ll j = max((l + p - 1) / p * p, 2ll * p); j <= r; j += p)
st[j - l] = true; //因为 l 不一定是从0 开始的, 所以要减去偏移量
}
cnt = 0;
for(int i = 0; i <= r - l; i ++)
{
if(!st[i] && i + l > 1) //1既不是质数也不是合数
primes[cnt ++] = i + l;
}
if(cnt < 2) puts("There are no adjacent primes.");
else
{
int minp = 0, maxp = 0;
for(int i = 0; i + 1 < cnt; i ++)
{
int d = primes[i + 1] - primes[i];
if(d < primes[minp + 1] - primes[minp]) minp = i;
if(d > primes[maxp + 1] - primes[maxp]) maxp = i;
}
printf("%d,%d are closest, %d,%d are most distant.\n", primes[minp], primes[minp + 1], primes[maxp], primes[maxp + 1]);
}
}
return 0;
}