解题思路
- 构造优于枚举:直接遍历 \(1\) 亿个数判断是否为回文质数会超时。更高效的方法是构造回文数,然后判断其是否为质数。
- 数学剪枝:
- 偶数位回文数性质:除了 \(11\) 以外,所有偶数位(4 位、6 位、8 位...)的回文数都能被 \(11\) 整除(例如 \(1221\),\(5775\)),因此一定不是质数。
- 最大范围:因为题目上限是 \(10^8\),而 8 位回文数可以直接跳过,所以我们只需要构造 1 位、2 位、3 位、5 位、7 位 的回文数。
- 首位判断:回文数的首位也是末位,偶数肯定不是质数(除了 2,但题目 \(a \ge 5\)),所以首位数字
d1 只能是 \(1, 3, 5, 7, 9\)。
AC 代码
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int a, b;
// 质数判断函数
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> a >> b;
// 优化:8位回文数必含因子11,故只需搜索到 10,000,000 (7位)
if (b > 10000000) b = 10000000;
// 1. 处理特殊的小数 (1位 和 2位)
// 只有 5, 7, 11 是我们需要关心的
int small[] = {5, 7, 11};
for (int x : small) {
if (x >= a && x <= b && isPrime(x)) cout << x << endl;
}
// 2. 构造 3 位回文数 (100~999)
// 形式: d1 d2 d1
for (int d1 = 1; d1 <= 9; d1 += 2) { // 首位必须是奇数
for (int d2 = 0; d2 <= 9; d2++) {
int p = d1 * 100 + d2 * 10 + d1;
if (p > b) return 0; // 超出范围直接结束程序
if (p >= a && isPrime(p)) cout << p << endl;
}
}
// 3. 构造 5 位回文数 (10000~99999)
// 形式: d1 d2 d3 d2 d1
for (int d1 = 1; d1 <= 9; d1 += 2) {
for (int d2 = 0; d2 <= 9; d2++) {
for (int d3 = 0; d3 <= 9; d3++) {
int p = d1 * 10000 + d2 * 1000 + d3 * 100 + d2 * 10 + d1;
if (p > b) return 0;
if (p >= a && isPrime(p)) cout << p << endl;
}
}
}
// 4. 构造 7 位回文数 (1000000~9999999)
// 形式: d1 d2 d3 d4 d3 d2 d1
for (int d1 = 1; d1 <= 9; d1 += 2) {
for (int d2 = 0; d2 <= 9; d2++) {
for (int d3 = 0; d3 <= 9; d3++) {
for (int d4 = 0; d4 <= 9; d4++) {
int p = d1 * 1000000 + d2 * 100000 + d3 * 10000 + d4 * 1000
+ d3 * 100 + d2 * 10 + d1;
if (p > b) return 0;
if (p >= a && isPrime(p)) cout << p << endl;
}
}
}
}
return 0;
}
关键点总结
- 跳过偶数位:代码中直接跳过了 4 位和 6 位的循环,因为它们除了 11 以外不可能是质数。
- 首位步长为 2:
d1 += 2 保证了生成的数是奇数,减少了一半的判断量。
- 即时终止:一旦生成的
p > b,直接 return 0 结束程序,因为后续生成的数只会更大。