Toy Code Plant

The quick brown fox jumps over the lazy dog.

Problem 95 Prime Palindromes

这个问题非常有趣,回文素数在数论里也占有一席之地,成为Palindromic Prime,或简写为Palprime。

题目的规模比之前的三道一下跳了n个数量级,达到100,000,000。不过因为只是在这个范围内做搜寻,所以并不用担心int的表示范围。但是,一亿还是很大的数字,一个个检测显然不现实,要想办法把范围缩小。首先,除了2,所有的素数都是奇数,而题目范围从5开始……Oh yeah,一下就干掉一半。俗话说好的开始是成功的一半,好兆头好兆头,hoho。接着,我们来看看回文数有什么特质:

1) 所有的个位素数都是Palprime,也就是2,3,5,7。
2) 两位回文素数只有一个,11,其他的如33,55,77等都是11的倍数。
3) 三位回文素数一共15个,分别是101,131,151,181,191,313,353,373,383,727,757,787,797,919,929。
4) 没有4位素数,实事上,偶数位的回文数全部都是11的倍数。因为一个偶数位的回文数必形如abba……E~~~我不知道怎么说了,奇数位的a+b一定等于偶数位的b+a……6位数也一样,abccba,依此类推吧-_-!。结论:11是唯一的偶位回文素数(好拗口)。
5) 五位回文素数有84个,最小的11311,最大的98689。

OK,看出一点端倪来了吧,我们只要把11单独列出来,就可以把所有偶数位数全部干掉。哦也again!再削掉一点,由于2是唯一的偶素数,所以回文素数除了2只能以奇数开头。

另外,即使在5位数10000~99999里,回文数也只有区区84个,可见回文数的数目比素数要少很多,而且,回文数是表面上就可以看出来的,而素数是自然数本身的性质,数字一大就很难直观的判断其素性。那么我们就可以不用一个个去试,而是自己动手把回文数create出来,再判断它是不是素数,如此以来,题目的规模就变得可以接受了。actually,Rob给的两个hints里也就是告诉你这么做。(想当初,Rob可没有那么kind,还给你hint…………鸡蛋!板砖!OKOK,不敢再倚老卖老了,最后一次,事不过三嘛~~~别踩,再踩就烂啦!)

现在来看看实事上我们要检查多少个数字,100,000,000是9位数,回文素数可能出现的区域实际上只有:2-9、11、101-999、10,001-99,999、1,000,001-9,999,999。每个区域内的回文数字都可以组合出来,分别是4,1,5×10,5×10×10,5×10×10×10。只有五千多个!最终的结果还要小,可见回文素数算得上是稀有族群了。

我用一个assemble函数来拼装回文数,它接受三个参数,分别是前缀1,前缀2和中间数。单独把前缀1列出来是因为回文素数开头和结尾都是奇数。重载一个双参数版本for 101-999。得到回文数后检查是不是落在要求的范围内,是不是素数,最后记得排序,因为拼装的数字并不是自然序列。

最后用三个for loop把它们包起来,你可以算一下i×j×k的积,看看和上面的组合数是不是一样的?

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;

int assemble(int, int);
int assemble(int, int, int);
int isprime(int);

int main(){
 int a,b;
 vector<int> array;

 ifstream fin("pprime.in");
 fin>>a>>b;
 
 if(a <= 5 && b >= 5) array.push_back(5);
 if(a <= 7 && b >= 7) array.push_back(7);
 if(a <= 11 && b >= 11) array.push_back(11);
 
 for(int i = 1; i < 10; i += 2){         // prefix1 or prefix
  for(int j = 0; j < 10; ++j){        // middle
   // 1.0.1-9.9.9
   int tmp = assemble(i, j);
   if(isprime(tmp) && tmp >= a && tmp <= b) array.push_back(tmp);
   
   for(int k = 0; k < 110; ++k){   // prefix2
    // 1.0.0.0.1-9.9.9.9.9:       0<=j<=9
    // 1.10.0.01.1-9.99.9.99.9:  10<=j<=99
    // 1.00.0.00.1-9.09.9.90.9: 100<=j<=109 TRICKY! Be careful!
    tmp = assemble(i, k, j);
    if(isprime(tmp) && tmp >= a && tmp <= b) array.push_back(tmp);
   }
  }
 } 
 sort(array.begin(),array.end());
 
 ofstream fout("pprime.out");
 vector<int>::const_iterator ci = array.begin();
 for(; ci != array.end(); ++ci) fout<<(*ci)<<endl;
}

// generate a palindrome
int assemble(int prefix, int middle){
 int result = prefix * 10 + middle; 
 while(prefix){
  result = result * 10 + prefix % 10;
  prefix = prefix / 10;
 }
 return result;
}

int assemble(int prefix1, int prefix2, int middle){
 int result, prefix;
 
 if(prefix2 < 10)
  prefix = prefix1 * 10 + prefix2;
 else if(prefix2 >= 100) //generate sequence: 00-09
  prefix = prefix1 * 100 + prefix2 % 100;
 else
  prefix = prefix1 * 100 + prefix2;

 result = prefix * 10 + middle;
 while(prefix){
  result = result * 10 + prefix % 10;
  prefix = prefix / 10;
 }
 return result;
}

int isprime(int i){
 if(i == 2) return 1;
 if(!(i%2)) return 0;
 for(int divisor = 3; divisor*divisor <= i; divisor += 2){
  if(!(i%divisor)) return 0;
 }
 return 1;
}

参考:http://hk.geocities.com/goodprimes/OBack.htm

阅读更多
个人分类: Algorithm in USACO
上一篇发现了一个好地方
下一篇所有计划搁浅,blog暂停更新
想对作者说点什么? 我来说一句

prime 算法 prime

2009年01月13日 2KB 下载

Prime Ring Problem 深度探索

2012年05月14日 2KB 下载

Performing Timing Analysis 3.pdf

2009年10月29日 609KB 下载

vega prime shader

2010年12月16日 818KB 下载

深度解读95后互联网生活方式

2018年04月28日 6.31MB 下载

C Prime plus 第五版(中文)

2013年11月28日 4.53MB 下载

C++ Prime中文版(第五版)

2016年04月03日 508B 下载

c++ prime 无水印版

2018年02月01日 98.33MB 下载

C++ Prime Plus中文版(第六版)

2017年04月02日 145B 下载

没有更多推荐了,返回首页

关闭
关闭