USACO Prime Palindrome, SuperPrime Rib

老規矩,先扯幾句淡。尋找回文質數還是蠻有趣的。可以先找回文數再判斷是否是質數,也可以先找出質數在判斷是否滿足迴文數性質,這些可以認爲是搜索的思路。我們知道,但凡問題要求找出全部解的時候,一般都意味着兩種思路,即搜索和構造。而通常情況下,搜索耗時會大很多,甚至空間耗費也要大不少,但是搜索的辦法思維不復雜,編程簡單。構造則相反,通常時空表現都好些,但是編程複雜很多,作爲ACMer,應該不怕這個,極致追求的是效率!效率!嘿嘿~再說構造,構造肯定是要充分利用數據的特性了,如果找到了比較好的特性——因而構造既易於實現也能保證答案的正確性與全面性——構造幾乎無一例外是優於搜索的。

pprimesprime都是關於構造法求全集的好例子。

pprime,迴文數的性質那是灰常明顯滴擺在那裏了——質數性質也很明顯,不過這個性質沒法子讓你使用構造法吧——不用構造法子手都癢。

我的大概思路是,設生成位數爲len的迴文數,若len是奇數,那麼從小到大枚舉(l+len) /2位的數,然後構造出一個迴文數;若len是偶數,那麼從小到大枚舉len/2位的數,然後複製翻轉生成一個迴文數(genepalin)。上訴兩個過程交替進行就可以從小到大生成迴文數了。

一些重要的剪枝是:任意偶數長度的迴文數都不可能爲質數(除了11),因爲它能被11整除,因爲11的整倍數有一個性質,那就是奇數位上數字之和等於偶數位上數字之和,一個數,如果是偶數長度迴文數,那麼同一個數num,必然出現在一次奇數位一次偶數位,所以這個偶數長度迴文數可以被11整除。還有一個優化:尾數爲5必不是質數,不過我給忘了用了。看速度還是很快的...

 

/*

ID: fairyroad

PROG: pprime

LANG: C++

*/

 

#include <fstream>

#include<cmath>

using namespace std;

ifstream fin("pprime.in");

ofstream fout("pprime.out");

 

size_t t[10] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};

size_t prime[10000] = {2};

size_t count = 1;

 

inline size_t length(size_t num){

    size_t res = 1;

    while(num/10){ ++res; num/=10; }

    return res;

}

 

inline size_t genepalin(size_t half){

    size_t lenh = length(half);

    size_t res = half * t[lenh];

    size_t len = lenh-1;

    while(len){

        res+=(half/t[len+1])*t[lenh - len];

        half%=t[len+1];

        --len;

    }

    return res;

}

 

inline void gene_prime(){

    for(size_t i = 3; i < 10001; ++i){

        bool flag = true;

        double d = sqrt((double) i);

        for (size_t j = 2; j <= d; j++)

            if(i%j==0){ flag = false; break;}

        if(flag) prime[count++] = i;

    }

}

 

inline bool is_prime(size_t num){

    if(num == 1) return false;

    for (size_t i = 0; i < count && prime[i] < num ; ++i)

        if(num%prime[i] == 0 && num != prime[i])

            return false ;

    return true;

}

 

int main(){

    size_t a, b;

    fin>>a>>b;

    gene_prime();

 

    size_t lena = length(a), lenb = length(b);

    size_t i, j;

    size_t tmp;

    for(i = lena; i < lenb+1; ++i){ // generate palindrome with length i

        if(i & 0x1u){ // odd

            j =  t[(i+1)/2];

            for(; j < t[(i+1)/2+1]; ++j){

                if(!(j/t[length(j)] & 0x1u)) continue;

                tmp = genepalin(j);

                if(tmp > b) return 0;

                if(tmp >= a && is_prime(tmp)) fout<<tmp<<endl;

            }

        }

        else{ // even

            if(i == 2) fout<<11<<endl;

        }

    }

 

    return 0;

}

 

sprime,同樣記住構造法的思路,質數的性質也很明顯的。那就是首位只能是質數2,3,5,7,其餘位只能是1,3,7,9。有了這個發現,程序也簡單了,我用的是深搜。速度很理想。構造萬歲呀!

/*

ID: fairyroad

PROG: sprime

LANG: C++

*/

 

#include<fstream>

#include<cmath>

using namespace std;

ifstream fin("sprime.in");

ofstream fout("sprime.out");

 

int opt[2][4] = {{2, 3, 5, 7}, {1, 3, 7, 9}};

int len;

 

inline bool is_prime(int num){

    if(num < 2) return false;

    double d = sqrt(num);

    for (int j = 2; j <= d; j++)

        if(num%j==0) return false ;

 

    return true;

}

 

void sprime(int n, int num){

    if(n == len){

        fout<<num<<endl;

        return;

    }

    for(int i = 0; i < 4; ++i){

        int tmp= num * 10 + opt[!!n][i];

        if(is_prime(tmp))

            sprime(n+1, tmp);

    }

}

 

int main()

{

    fin>>len;

    sprime(0, 0);

    return 0;

}

 

微博: http://t.sina.com.cn/g7tianyi

del.icio.us: http://delicious.com/fairyroad

豆瓣:http://www.douban.com/people/Jackierasy/

e-mail: [email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章