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;
}
}
}