P1217 [USACO1.5]回文质数 Prime Palindromes

题目描述

因为 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](5a<b100,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 5a<b100,000,000 ) ,达到了108 ,这种情况下,常用的质数判断方法都会超时。

就没有办法高效地找出回文质数了吗?
分析回文质数的特点:

  1. 回文 :从左到右和从右到左是看一样的
  2. 质数

回文这么特别,完全可以构造出来啊!
比如,由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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值