题面描述
老顽童是一个热爱运动的人,每天都有小顽童来和他一起锻炼。为了让锻炼更有成效,他想要制定一份锻炼计划,让第 n 天的训练量要等于第 n 个正回文数 ( 第 1 个正回文数是 1) 。
老顽童已经打印好了计划表,但是他的计划表中有一些日子被遗漏了,他又不想重新计算,你可以帮他解决这个问题吗?
如果一个数的各位数字反向排列后仍然等于其本身,则把这样的数称为回文数 (palindrome number) ,如 12321 是回文数, 1232 不是回文数。
输入数据
第一行有一个整数 t (1 ≤ t ≤ 100000) ,表示有 t 组数据。
每组数据只有一行,为一个整数 n (1 ≤ n ≤ 400000) ,表示第 n 天。
输出数据
对于每组数据,输出一个整数,表示对应的训练量。
样例输入
5
1
2
3
12
23
样例输出
1
2
3
33
141
解题思路
自然序列中的有序的第N个回文数,400000这个还是蛮大的。在一切循环都会超时的情况下,采用打表的方式,获取有序回文数的构成位数。经过规律探索发现,//*说明:第N个回文数是个num位数,奇数位前半部分front_num =(num+1)/ 2,偶数位前半部分behind_num =num / 2。定位打表的位置后,求出num位数的序号,dif = n - arr[num-1] 。*//
回文数的前半部分 == {pow(10 , front_num-1)或者} pow(10 , front_num-1) + dif - 1 。
示例:第333个回文数是23432。
先打表定位:198 < 333 < 1098 ;表示一个num= 5位数。而且arr[5-1] = 198。
那么,dif = 333 - 198 = 135 。
那么,前半部分front_num = (5+1)/ 2 = 3 。
总述:front = pow(10 , 2) + dif - 1 = 100 + 135 - 1 = 234
另外:dif = n - arr[num] = 333 - 1098 = -765
front = pow(10 , front_num) + dif - 1 = pow(10 , 3) + (-765) - 1 = 1000 - 765 - 1 = 234
代码一与代码二的原理基本一致,打表求位置。需要注意的是:int整型的长度,求出前半部分front后,直接输出即可,紧接着输出后半部分behind。不要front+behind相加后再输出,会造成超出范围Wrong Answer 。
程序代码一
#include <iostream>
using namespace std;
void Huiwen(int n){
int s = 9 , ans = 1 ;
while(n > s * 2)// 判断第n个数有多少位,原理等同于打表求值
{
n -= s * 2 ;
s *= 10 ;
ans *= 10 ;
}
ans += (n % s == 0 ? s : n % s) - 1 ;// a>b?a:b 说明:a>b为true返回a,否则b
cout << ans ;// 输出前半部分
if(n - s <= 0)// n个位数为奇数,去掉最后一位
ans /= 10 ;
while(ans)
{
cout << ans % 10 ;//输出后半部分
ans /= 10 ;
}
cout << endl ;
}
int main(){
int t ;// t组数据
cin >> t ;
for (int i = 0 ; i < t ; i++){
int n ;
cin >> n ;
Huiwen(n) ;
}
return 0 ;
}
程序代码二
图中打表的代码,完整版如下
int arr[12] = {0 , 9 , 18 , 108 , 198 , 1098 , 1998 , 10998 , 19998 , 109998 , 199998 , 1099998} ;
// 位数表 0-1-2-3-4-5-6-7-8-9-10-11