题目描述
因为 151 151 151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 151 151 是回文质数。
写一个程序来找出范围 [ a , b ] ( 5 ≤ a < b ≤ 100 , 000 , 000 ) [a,b] (5 \le a < b \le 100,000,000) [a,b](5≤a<b≤100,000,000)(一亿)间的所有回文质数。
输入格式
第一行输入两个正整数 a a a 和 b b b。
输出格式
输出一个回文质数的列表,一行一个。
样例输入
5 500
样例输出
5
7
11
101
131
151
181
191
313
353
373
383
提示
-
Hint 1: Generate the palindromes and see if they are prime.
-
提示 1: 找出所有的回文数再判断它们是不是质数(素数).
-
Hint 2:Generate palindromes by combining digits properly. You might need more than one of the loops like below.
-
提示 2:要产生正确的回文数,你可能需要几个像下面这样的循环产生长度为 5 5 5 的回文数:
for (d1 = 1; d1 <= 9; d1+=2) { // 只有奇数才会是素数
for (d2 = 0; d2 <= 9; d2++) {
for (d3 = 0; d3 <= 9; d3++) {
palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
}
}
}
思路分析
本题的数据范围非常大 (
5
≤
a
<
b
≤
100
,
000
,
000
5 \le a < b \le 100,000,000
5≤a<b≤100,000,000 ) ,达到了108 ,这种情况下,常用的质数判断方法都会超时。
就没有办法高效地找出回文质数了吗?
分析回文质数的特点:
- 回文 :从左到右和从右到左是看一样的
- 质数
回文这么特别,完全可以构造出来啊!
比如,由1234,可以构造出回文数 12344321 或者 1234321。也就是说从1位数枚举到4位数,就可以构造出9位以内的所有回文数了。时间复杂度一下子就从108 降到了104 。
枚举的过程中,每构造一个回文数,就判断一下它是不是质数,如果是质数,就输出。
100以内的回文质数只有5、7、11 。剩下的2位回文都是11的倍数,不是质数。
另外,所有 偶数个 位数的回文都是11的倍数。
这是因为11的倍数满足这样的特点:奇数位 上的数字之和与 偶数位 上的数字之和的 差 (以大减小)是0或是11的倍数。
偶数个 位数的回文数由于是对称的。所以,奇数位 上的数字之和与 偶数位 上的数字之和 一定相等,那么它们的差就是 0 。所以,一定是11的倍数。
比如,123321 ,1+3+2 - 2+3+1 = 0。
所以代码中,只需处理5、7、11、3位回文数、5位回文数和7位回文数即可。
参考代码
#include<iostream>
using namespace std;
bool isPrime(int n) {
//n是奇数,从3开始判断即可
for (int i = 3; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
int main() {
//读入区间
int a, b;
cin >> a >> b;
//1. 100以内的回文质数只有5、7、11。22、33...99 都是11的倍数,不是质数。
if (a <= 5 && b >= 5) cout << 5 << endl;
if (a <= 7 && b >= 7) cout << 7 << endl;
if (a <= 11 && b >= 11) cout << 11 << endl;
//2.处理3位回文数,枚举2位
//第1位和最后1位一样,最后1位不可能是2的倍数,因为偶数肯定不是质数,只枚举奇数即可
for (int i = 1; i <= 9; i += 2) { //百位
for (int j = 0; j <= 9; j++) { //十位
int n = 100 * i + 10 * j + i; //构造回文数
if (n < a) continue; //在[a,b]的左边,丢弃
if (n > b) return 0; //在[a,b]的右边,说明枚举完了,结束程序
//在[a,b]内,判断是不是质数,是质数就输出
if (isPrime(n))
cout << n << endl;
}
}
//3. 处理5位回文数,枚举3位
for (int i = 1; i <= 9; i += 2) { //枚举最高位
for (int j = 0; j <= 9; j++) { //枚举次高位
for (int k = 0; k <= 9; k++) { //枚举中间位
int n = 10000 * i + 1000 * j + k * 100 + j * 10 + i; //构造回文数
if (n < a) continue; //在[a,b]的左边,丢弃
if (n > b) return 0; //在[a,b]的右边,说明枚举完了,结束程序
//在[a,b]内,判断是不是质数,是质数就输出
if (isPrime(n))
cout << n << endl;
}
}
}
//4. 处理7位回文数,枚举4位
for (int i = 1; i <= 9; i += 2) { //枚举最高位
for (int j = 0; j <= 9; j++) { //枚举次高位
for (int k = 0; k <= 9; k++) { //枚举次次高位
for (int m = 0; m <= 9; m++) { //枚举中间位
//构造回文数
int n = 1000000 * i + 100000 * j + k * 10000 + m * 1000 + k * 100 + j * 10 + i;
if (n < a) continue; //在[a,b]的左边,丢弃
if (n > b) return 0; //在[a,b]的右边,说明枚举完了,结束程序
//在[a,b]内,判断是不是质数,是质数就输出
if (isPrime(n))
cout << n << endl;
}
}
}
}
return 0;
}