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

这是一道很迷的题,测试数据最大的是1亿,然后,用1亿会超时,用1千万居然就可以了。还有,如果输入数据超过1亿,设置为1千万,居然AC了,奇葩!


题目描述

因为151既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 是回文质数。

写一个程序来找出范围[a,b](5 <= a < b <= 100,000,000)( 一亿)间的所有回文质数;

输入输出格式

输入格式:

第 1 行: 二个整数 a 和 b .

输出格式:

输出一个回文质数的列表,一行一个。

输入输出样例

输入样例#1:

5 500

输出样例#1:

5
7
11
101
131
151
181
191
313
353
373
383


//100000000
#include <iostream>
#include <cmath>
#include <cstring>
//              10000005
#define MAX_NUM 10000005
using namespace std;

bool prime[MAX_NUM];
int tem[MAX_NUM];
int cnt = 0;

void setPrime() {
	memset(::prime, 1, sizeof(::prime));
	::prime[0] = ::prime[1] = false;
	for (int i = 2; i < MAX_NUM; i++) {
		if (::prime[i]) {
			tem[cnt] = i;
			cnt++;
		}
		for (int j = 0; j < cnt&&tem[j] * i < MAX_NUM; j++) {
			prime[i*tem[j]] = false;
			if (i%tem[j] == 0) break;
		}
	}
}

bool isPhNum(int n) {
	int temp = n;
	int k = 0;
	while (n) {
		k = k * 10 + n % 10;
		n /= 10;
	}
	return k == temp ? true : false;
}

int main() {
	setPrime();
	int a,b;
	cin >> a >> b;
	if (b>10000000) b = 10000000;
	if (a % 2 == 0) a = a + 1;
	for (int i = a; i <= b; i+=2) {
		if (isPhNum(i) && prime[i])
			cout << i << endl;
	}
	return 0;
}

附:素数筛选法,整体不难,但关键 要知道一个合数可以化为两个数相乘,一个较大数,一个较小数。咱们这里采用较小数取合数,那么就会出现if(i % prime[j]==0) break;这样的语句了,我们不采用较大数操作。

void Prime(){
	memset(tag,0,sizeof(tag));
	int cnt=0;
	//标明 0 1 为合数 
	tag[0]=tag[1]=1;
	
	for(int i = 2; i<N; i++){
		if(tag[i] == 0)		// 如果当前此为素数
			prime[cnt++]=i; // 存入prime数组
		// 精华
		for(int j=0;j<cnt && prime[j]*i<N; j++){
			// 之前确定的素数与这个数进行相乘
			tag[i*prime[j]] = 1;
			//关键代码,因为如果i能整出prime[j],那么i肯定是个合数,
			//且i中有质因子肯定小于等于prime[j],
			//所以到此就可以停止了,因为后面的prime[]会比i小的那个质因子要大。
			if(i % prime[j]==0)
				break;
		}
	}
}

原文地址:https://www.cnblogs.com/laohaozi/p/12537726.html