题目-质数距离

问题分析
因为 U U U的范围是 2 31 − 1 2 ^ {31} - 1 231−1级别的, 筛质数算法时间复杂度最优 O ( n ) O(n) O(n), 没办法在规定时间内处理所有的质数, 并且线性筛法只能从 2 2 2开始筛, 不能只筛一个区间
注意到, R − L ≤ 1 0 6 R - L \le 10 ^ 6 R−L≤106, 长度很小, 需要对筛法进行改进, 对于一个数的因子对 [ d , n d ] [d, \frac{n}{d}] [d,dn], 假设 d ≤ n d d \le \frac{n}{d} d≤dn, 一个数的任意因子对 [ d , n d ] [d, \frac{n}{d}] [d,dn] , 一定存在 d ≤ n d \le \sqrt n d≤n
算法步骤
- 找出 [ 1 , n ] [1, \sqrt n] [1,n]的质因子, 大概是 5 × 1 0 4 5 \times 10 ^ 4 5×104级别
- 对于 [ L , R ] [L, R] [L,R]中的合数, 一定存在质因子在 [ 1 , n ] [1, \sqrt n] [1,n]之间, 将 [ L , R ] [L, R] [L,R]之间质因子的倍数筛掉
- 对于 [ L , R ] [L, R] [L,R]枚举质数之间的距离统计答案
n 2 + n 3 + n 5 + . . . + n n = n log log n \frac{n}{2} + \frac{n}{3} + \frac{n}{5} + ... + \frac{n}{\sqrt n} = n\log \log \sqrt n 2n+3n+5n+...+nn=nloglogn
算法时间复杂度 O ( n + n log log n ) O(\sqrt n + n\log \log \sqrt n) O(n+nloglogn)
计算 ≥ l \ge l ≥l最小的 p p p的倍数, 也就是计算 ⌈ l p ⌉ × p \left \lceil \frac{l}{p} \right \rceil \times p ⌈pl⌉×p
利用等式 ⌈ l p ⌉ = ⌊ l + p − 1 p ⌋ \left \lceil \frac{l}{p} \right \rceil = \left \lfloor \frac{l + p - 1}{p} \right \rfloor ⌈pl⌉=⌊pl+p−1⌋, 分情况讨论, 如果 l ∣ p l | p l∣p, 相当于没加, 如果 l l l不是 p p p的倍数, l m o d p = r l \mod p = r lmodp=r, r ≥ 1 r \ge 1 r≥1, 因此结果会 + 1 + 1 +1, 也就是达到了上取整的效果
代码实现
注意: val的值可能会爆 i n t int int, 需要开 l o n g l o n g long long longlong
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, M = 50010;
int l, r;
int primes[N], cnt;
bool st[N];
void init(int k) {
for (int i = 2; i <= k; ++i) {
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j] <= k / i; ++j) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
void solve() {
memset(st, false, sizeof st);
cnt = 0;
init(M);
memset(st, false, sizeof st);
for (int i = 0; i < cnt; ++i) {
LL p = primes[i];
LL val = max(2 * p, ((l + p - 1) / p) * p);
for (LL j = val; j <= r; j += p) {
st[j - l] = true;
}
}
cnt = 0;
for (int i = 0; i <= r - l; ++i) {
if (!st[i] && i + l >= 2) primes[cnt++] = i + l;
}
if (cnt < 2) {
printf("There are no adjacent primes.\n");
return;
}
int minv = 0, maxv = 0;
for (int i = 0; i < cnt - 1; ++i) {
int d = primes[i + 1] - primes[i];
if (d < primes[minv + 1] - primes[minv]) minv = i;
if (d > primes[maxv + 1] - primes[maxv]) maxv = i;
}
printf("%d,%d are closest, %d,%d are most distant.\n", primes[minv], primes[minv + 1], primes[maxv], primes[maxv + 1]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> l >> r) solve();
return 0;
}

京公网安备 11010502036488号