1. 程式人生 > >【USACO1.6.3】Prime Palindromes【數論,數學】【模擬】

【USACO1.6.3】Prime Palindromes【數論,數學】【模擬】

題目大意:

題目連結:http://train.usaco.org/usacoprob2?a=iLZIJL4lyhX&S=pprime
l l r r 之間的迴文質數。


思路:

由於 100000000

100000000 之內有 5761455 5761455 個質數,而且我懶到不想打線性篩,所以就只能先篩迴文再篩質數。
迴文數很好篩。先把它的每一位儲存到數組裡,然後再用兩個指標判斷它是否迴文即可。
質數的話就一邊根號過去就可以了。
但是這樣會T三個點。
其實,除了11以外的偶數位迴文數都是11的倍數

證明:
先設出一般形式: a

n . . . a 2 a 1 a 1
a 2... a n an...a2a1a1a2...an
然後可將其改寫(首尾兩兩依次配對):
a n . . . a 2 a 1 a 1 a 2... a n = a n × ( 1 0 ( 2 n 1 ) + 1 ) + . . . + a 2 × ( 1 0 ( 2 × 2 1 ) + 1 ) × 1 0 ( n 2 ) + a 1 × ( 1 0 ( 2 × 1 1 ) + 1 ) × 1 0 ( n 1 ) an...a2a1a1a2...an=an\times(10^{(2n-1)}+1)+...+a2\times(10^{(2\times2-1)}+1)\times10^{(n-2)}+a1\times(10^{(2\times1-1)}+1)\times10^{(n-1)}
可以看到求和的每一項均有因式 1 0 ( 2 k 1 ) + 1 10^{(2k-1)}+1 ,而該因式又含有因式 10 + 1 = 11 10+1=11 ,故和是 11 11 的倍數.

那麼就剪個枝就好了。


程式碼:

/*
ID:ssl_zyc2
TASK:pprime
LANG:C++
*/

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

int l,r;

bool check(int x)
{
    int a[101],len=0,y=x;
    memset(a,0,sizeof(a));
    while (y)  //求出每一位
    {
        a[++len]=y%10;
        y/=10;
    }
    for (int i=1;i<=len/2;i++)
     if (a[i]!=a[len-i+1]) return 0;  //判迴文
    for (int i=2;i<=sqrt(x);i++)
     if (!(x%i)) return 0;
    return 1;
}

int main()
{
    scanf("%d%d",&l,&r);
    for (register int i=l;i<=r;i++)
    {
        if (i==1000||i==100000||i==10000000) i*=10;  //不能為偶數位(兩位除外)
        if (i>r) break;
        if (i>1&&check(i)) printf("%d\n",i); 
    } 
    return 0;
}