1 条题解
-
0
思路与算法
先筛出2至46340的质数,因为R<2^31,其平方根不超过这个值。对每个[L,R]创建布尔段,依次用小质数p标记其倍数,起点为max(p²,ceil(L/p)*p)。单独排除1,再从左到右扫描剩下的质数,比较相邻差,分别维护最小和最大差对应数对;相等时不更新。
正确性说明
区间内任意合数都有一个不超过sqrt(R)的质因子,因而一定被某轮标记。起点不小于p²,避免把p自身误删,区间内质数均保留。递增扫描使每一对相邻质数恰好比较一次,严格更新保留最先出现的并列数对。若不足两质数,没有相邻数对,输出指定英文句子。
复杂度
设B=46340、W=R-L+1≤1000001。预筛初始化O(B),筛法O(B log log B),每组段初始化O(W),标记约O(W log log R+π(sqrt(R))),扫描O(W)。空间O(B+W),多组复用小质数表。起点乘法、p²与区间端点用long long,防止32位中间计算溢出。
易错点
1不是质数,L本身若为小质数不能删除。closest与most distant并列时取靠前数对。逗号后、句点和英文大小写按样例输出。独立答案逐整数用32位范围确定性的Miller-Rabin底数2、3、5、7、11验证,未复用分段筛标记结果。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { const int cap = 46340; vector<bool> isPrime(cap + 1, true); vector<int> primes; for (int i = 2; i <= cap; ++i) if (isPrime[i]) { primes.push_back(i); for (long long j = 1LL * i * i; j <= cap; j += i) isPrime[j] = false; } long long L, R; while (cin >> L >> R) { vector<bool> ok(R - L + 1, true); for (long long p : primes) { if (p * p > R) break; for (long long j = max(p * p, (L + p - 1) / p * p); j <= R; j += p) ok[j - L] = false; } if (L == 1) ok[0] = false; long long last = -1, al = -1, ar = 0, bl = -1, br = 0; for (long long x = L; x <= R; ++x) if (ok[x - L]) { if (last >= 0) { if (al < 0 || x - last < ar - al) { al = last; ar = x; } if (bl < 0 || x - last > br - bl) { bl = last; br = x; } } last = x; } if (al < 0) cout << "There are no adjacent primes.\n"; else cout << al << ',' << ar << " are closest, " << bl << ',' << br << " are most distant.\n"; } }
- 1