给定一个数,求一个新数要大于等于这个数,而这个新数既要是palindromes回文又要是prime素数。
题目很简单,有人都使用取巧的方法保存好结果直接查表。
或者暴力法求解。
这里不使用保存表的方法,也不要用暴力法。- 这些方法都不好。
使用的技巧有:
1 而是使用next palindrome的技巧,只需要O(n),n是数位,可以认为是常数了。
2 判断素数的方法,时间效率是O(sqrt(n)), n是数值大小,如果是重复判断很多数是否是素数是有办法优化的,但是如果是单个素数判断的话,我还想不到,也找不到优化的方法。
不过怎么都好,下面程序假设它是需要重复判断数是素数的,那么就可以保持一个数组的方法,然后只需要判断这个数是否能被这个数组中小于这个数n的sqrt(n)除尽,就可以快速判断出这个数是否是素数了。
当然本题好像直接判断是否是素数就可以了。
原题:http://www.codechef.com/problems/PRPALIN/
全部实现上面的优化,那么程序还是非常繁琐的,也是出于学习的目的吧。
#include <assert.h>
#include <string>
#include <stdio.h>
#include <math.h>
#include <iostream>
using namespace std;
namespace{
static const int MAX_NUM = 1100;
}
bool allNines(string a)
{
bool nines = true;
for (int i = 0; i < (int)a.size() && nines; i++)
{
if (a[i] != '9') nines = false;
}
return nines;
}
string nextPalindrome(string a)
{
if (allNines(a))
{
a[0] = '1';
for (int i = 1; i < (int)a.size(); i++)
{
a[i] = '0';
}
a.push_back('1');
return a;
}
int mid = (a.size() >> 1);
int L = mid - 1, R = mid + 1;
if (a.size() % 2 == 0) R--;//确定中心
int i = L, j = R;//查找不同点下标
for ( ; i >= 0 && j < (int)a.size() && a[i] == a[j]; i--, j++);
bool leftsmall = false;
if (i < 0 || a[i] <= a[j]) leftsmall = true;//i<0排除了等于的情况了
for ( ; i >= 0; i--, j++)
{
a[j] = a[i];
}
if (leftsmall)
{
int carry = 1;
if (a.size() % 2)
{
a[mid]++;
if (a[mid] > '9') a[mid] = '0';
else carry = 0;
}
i = L, j = R;
while (carry)
{
a[i]++;
if (a[i] > '9') a[i] = '0';
else carry = 0;
a[j] = a[i];
i--, j++;
}
}
return a;
}
bool isPalindrome(string s)
{
bool palin = true;
for (int i = 0, j = int(s.size()) - 1; i < j; i++, j--)
{
if (s[i] != s[j]) palin = false;
}
return palin;
}
int PrimePalindromes()
{
bool primes[MAX_NUM+1] = {0};
for (int i = 2; i <= MAX_NUM; i++)
{
if (!primes[i])
{
for (int j = (i<<1); j <= MAX_NUM; j += i)
{
primes[j] = true;
}
}
}
int primeNums[MAX_NUM] = {0};
int id = 0;
for (int i = 2; i <= MAX_NUM; i++)
{
if (!primes[i]) primeNums[id++] = i;
}
string s;
cin>>s;
int sn = stoi(s);
assert(1 <= sn && sn <= 1000000);
if (!isPalindrome(s)) s = nextPalindrome(s);
while (true)
{
sn = stoi(s);
int sq = (int)sqrt((double)sn);
bool isprimeNum = true;
int i = 0;
for ( ; primeNums[i] <= sq && i < id; i++)
{
if (sn % primeNums[i] == 0)
{
isprimeNum = false;
break;
}
}
if (isprimeNum) break;
s = nextPalindrome(s);
}
cout<<s;
return 0;
}