引入问题:
给定两个整数L和U,你需要在闭区间[L,U]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。
同时,你还需要找到距离最远的两个相邻质数D1和D2(即D1-D2是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。
1
≤
L
<
U
≤
2
31
−
1
,
U
−
L
∈
[
0
,
1
e
6
]
1≤L<U≤2^{31}−1,U-L\in[0,1e6]
1≤L<U≤231−1,U−L∈[0,1e6]
解题思路:
(1)
2
31
−
1
≈
1
e
9
2^{31}-1\approx1e9
231−1≈1e9无论是欧拉筛还是埃氏筛法都是从
[
1
,
n
]
[1,n]
[1,n]开始筛的,这个数据范围都是无法接受的
(2)很明显如果这个一个数的是合数:那么这个数一定有一个质因子
d
<
=
n
d<=\sqrt n
d<=n
(3)那么我们就先把
[
1
,
n
]
[1,\sqrt n]
[1,n]内的素数筛出来
1
e
9
≈
5
e
4
\sqrt {1e9}\approx5e4
1e9≈5e4可以接受
(4)那么我们就把这些素数去筛
[
L
,
U
]
[L,U]
[L,U]的素数
(5)根据埃氏筛法我们要找到
[
L
,
U
]
[L,U]
[L,U]这个区间内第一个大于质数
p
p
p,并且是
p
p
p的倍数之后就每次
+
p
+p
+p一次筛下去;
(6)第一个大于
p
p
p并且是
p
p
p的倍数
⌈
L
p
⌉
∗
p
≈
⌊
L
+
p
−
1
p
⌋
∗
p
\lceil {L\over p} \rceil*p\approx\lfloor {L+p-1\over p} \rfloor*p
⌈pL⌉∗p≈⌊pL+p−1⌋∗p
(7)因为数很大我们可以让
[
[
[区间整体
−
L
]
∈
[
0
,
1
e
6
]
-L]\in[0,1e6]
−L]∈[0,1e6]
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 6e6 + 10;
long long prime[N], cnt;
bool vis[N];
void init(int n)
{
cnt = 0;
memset(vis,0,sizeof (vis));
for(int i = 2; i <= n; ++ i)
{
if(!vis[i]) prime[cnt ++] = i;
for(int j = 0; j < cnt && i * prime[j] <= n; ++ j)
{
vis[i * prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
}
int main()
{
long long l, r;
while(cin >> l >> r)
{
init(50000);//Eula筛
memset(vis,0,sizeof (vis));
for(int i = 0; i < cnt; ++ i)
{
long long p = prime[i];
for(long long j = max(2 * p, (l + p - 1) / p * p); j <= r; j += p)
vis[j - l] = true;//减去偏移量
}
cnt = 0;
for(long long i = 0; i <= r - l; ++ i)
if(!vis[i] && i + l >= 2)
prime[cnt ++] = i + l;
int maxp = 0, minp = 0;
for(int i = 0; i < cnt - 1; ++ i)
{
int d = prime[i + 1] - prime[i];
if(d > prime[maxp + 1] - prime[maxp]) maxp = i;
if(d < prime[minp + 1] - prime[minp]) minp = i;
}
if(cnt < 2) puts("There are no adjacent primes.");
else
{
cout << prime[minp] << "," << prime[minp + 1] << " are closest, ",
cout << prime[maxp] << "," << prime[maxp + 1] << " are most distant.\n";
}
}
return 0;
}