题解:学而思编程 回文质数(一)
【题目来源】
学而思编程:回文质数(一)
【题目描述】
小猴最近在编程课上学习了回文数,并且在数学课上学习质数。
小猴想要知道在 \(L\sim R\) 之间(包含 \(L\) 和 \(R\)),其中有多少个数既是回文数又是质数。请你帮助小猴解答他疑惑。
【输入】
一行两个整数 \(L\),\(R\)。
【输出】
一行一个整数,表示在 \(L\sim R\) 之间(包含 \(L\) 和 \(R\)),其中有多少个数既是回文数又是质数。
【输入样例】
7 11
【输出样例】
2
【核心思想】
-
问题分析:给定区间 \([L, R]\),统计其中既是回文数又是质数的数的个数。这是一个回文数构造 + 质数判定问题,关键在于高效生成回文数而非遍历整个区间,再对每个回文数判断是否为质数。
-
算法选择:
- 回文数构造:通过"前半部分 + 镜像"的方式生成回文数,避免遍历全部数字
- 质数判定:对每个生成的回文数,用试除法到 \(\sqrt{x}\) 判断是否为质数
- 奇偶长度分类:分别构造奇数长度和偶数长度的回文数
-
关键步骤:
- 初始化:读取 \(L\) 和 \(R\)
- 回文数构造(遍历 \(i\) 从 \(0\) 到 \(999\)):
- 奇数长度回文:
work(i, i),将 \(i\) 作为前半部分,镜像拼接。例如 \(i = 123\),生成 \(12321\) - 偶数长度回文:
work(10 * i + j, i),在 \(i\) 和镜像之间插入中间数字 \(j\)(\(0 \leq j \leq 9\))。例如 \(i = 12, j = 3\),生成 \(12321\)
- 奇数长度回文:
- work 函数:
- 将后半部分 \(b\) 的数字反向添加到 \(a\) 后面,构造完整回文数
- 若回文数在 \([L, R]\) 内且是质数:
ans++
- 质数判定
isprime(x):- 若 \(x \leq 1\):返回
false - 遍历 \(i\) 从 \(2\) 到 \(\sqrt{x}\):若 \(x \bmod i = 0\) 则返回
false - 否则返回
true
- 若 \(x \leq 1\):返回
- 输出
ans
-
时间/空间复杂度:
- 时间复杂度:\(O(1000 \times 10 \times \sqrt{R})\),生成约 \(10000\) 个回文数,每个质数判定 \(O(\sqrt{R})\)
- 空间复杂度:\(O(1)\),仅需常数变量
-
回文数构造的核心思想:
- 生成优于枚举:直接构造回文数的数量远小于区间内的数字总数(尤其大区间时),大幅降低搜索空间
- 镜像拼接:回文数的前半部分唯一确定整个数,通过数字反转和拼接实现构造
- 奇偶分类:奇数长度回文有中心数字,偶数长度无中心数字,分别用
work(i, i)和work(10*i+j, i)覆盖 - 范围过滤:构造后立即检查是否在 \([L, R]\) 内,避免无效质数判定
- 适用于"回文数 + 其他约束"的计数问题,构造法将线性枚举优化为对数级生成
【算法标签】
质数
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int l, r, ans; // 查询区间[l,r],答案ans
// 判断素数
bool isprime(int x)
{
if (x <= 1) return false; // 小于等于1不是素数
for (int i = 2; i * i <= x; i++) // 检查到√x
{
if (x % i == 0) return false; // 有因数,不是素数
}
return true; // 是素数
}
// 构造回文数并判断
int work(int a, int b)
{
while (b > 0) // 将b的数字反向添加到a后面
{
a = a * 10 + b % 10; // 将b的最后一位加到a
b /= 10; // 去掉b的最后一位
}
// 检查a是否在区间内且是素数
if (l <= a && a <= r && isprime(a) == true)
{
return 1; // 满足条件
}
else
{
return 0; // 不满足条件
}
}
signed main()
{
cin >> l >> r; // 输入查询区间
// 生成所有可能的回文数
for (int i = 0; i < 1000; i++) // 生成3位数以内的回文基础
{
// 奇数长度回文:work(i, i) 如12321
ans += work(i, i);
// 偶数长度回文:work(10*i+j, i) 如123321
for (int j = 0; j <= 9; j++) // 中间插入数字j
{
ans += work(10 * i + j, i);
}
}
cout << ans << endl; // 输出结果
return 0;
}
【运行结果】
7 11
2
浙公网安备 33010602011771号