您的位置:首页 > 其它

NOJ1046第K回文数——???

2014-06-10 22:29 211 查看

第K回文数

Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByte

Total Submit:612 Accepted:150

Description

回文数是这样一个正整数:它从左往右读和从右往左读是一样的。例如1,111,121,505都是回文数。将1到100,000,000内所有回文数按从小到达排序后,第k个回文数是多少呢?

Input

第一行为一个整数N,表示询问的次数。以下N行每行一个整数k,表示询问第k个回文数是多少。

Output

输出共N行,按照输入数据的顺序,依次输出第k个回文数。

Sample Input
2

5

10
Sample Output
5

11
Source
NUAA

分析:找规律。
1位数中回文数有9个:1,2,3,4,5,6,7,8,9
2位数中回文数有9个:11,22,33,44,55,66,77,88,99
3位数中回文数有90个:101,111,121,131,141,151,161,171,181,191;202,212,222。。。;909,919,929,939,949,959,969,979,989,999。
4位数中回文数有90个
。。。
相邻的位数中的回文数个数相同,且是10倍递增的。其次,同一位数里面的回文数的增长也是有规律的。如:101,111,121,131。。。

如果直接求出回文数存在数组里。莫名其妙的Wrong Answer!
下面给出比较好的写法,运行时间为0MS:
如k=224时,第K回文数为12521。先求出第K回文数的位数,再求出该数的左半边,因为对称,再求出右半边。(注意位数为奇数的情况)。最终的结果即为答案。

有意思的是:k减去每个位数的回文数的时候,如k-9-90-90-900-900。。。当k继续减位数时,k<0 那么就能确定第K回文数的个数,同时,这个回文数的左半边的除最高位之外的数也确定了。举例:
如k=224时,k-10-10-90-90>0,再减去900就小于0了,所以确定第224个回文数是5位数。同时,这个数的左半边的位数也能确定为3((5+1)/2)。且这个数的左半边是从100(因为左半边为3位)开始的第(k-10-10-90-90-1)个数。
所以这个数的左半边能确定了,实际即为100+25=125。
接下去的任务就是对称把右半边求出来。再整合即得到答案ans。这边的求右半边的数的写法比较nice!

反过来,如果给定12521,求它是第几个回文数,解法应该为:
解:因为12521为5位数,所以在它之前有9+9+90+90个数。12521在5位数中是10+10+6个。(0 1 2 3 4 5)
所以12521为第(9+9+90+90+10+10+6)= 224 个。

#include<stdio.h>

//第K回文数

void fun(int k)
{
int half_len, left, weishu, num, ans = 0;
num = 9; // 几位数对应多少回文数 1-9,2-9,3-90,4-90...
for(weishu=1;k-num>0;weishu++) // 有几位,1开始 求出第k个回文数的位数
{
// 对应的回文数 > k
k -= num;
if(weishu % 2 == 0) // 1位-9个,2位-9个,3-90,4-90...每2个增量为10倍
num *= 10;
}
half_len = (weishu+1) / 2; // 回文数的位数的一半,如12521为3
left = 1; // 回文数的左边一半,如12521中的125

for(int i=2;i<=half_len;i++)
left *= 10;
left += k-1; // 125

ans += left; // 125
if(weishu % 2 != 0) // 位数为奇数,左半边比右半边多一位
left /= 10; // 12
while(left)
{
ans = ans*10 + left%10; // (125*10+2)*10+1
left /= 10;
}
printf("%d\n",ans);
}

int main()
{
int n, k;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&k);
fun(k);
}
return 0;
}


还有一种比较清晰但是略烦的写法:

#include<stdio.h>
int main()
{
int n,j,i,k;
scanf("%d",&n);
while(n--)
{
scanf("%d",&k);
if(k <= 9)
;
else if(k <= 18)
k=(k-10)*11+11;
else if(k <= 108)
k=((k-19)/10+1)*101+(k-19)%10*10;
else if(k <= 198)
k=((k-109)/10+1)*1001+(k-109)%10*110;
else if(k <= 1098)
k=((k-199)/100+1)*10001+(k-199)/10%10*1010+(k-199)%10*100;
else if(k <= 1998)
k=((k-1099)/100+1)*100001+(k-1099)/10%10*10010+(k-1099)%10*1100;
else if(k <= 10998)
k=((k-1999)/1000+1)*1000001+(k-1999)/100%10*100010+(k-1999)%10*1000+(k-1999)/10%10*10100;
else if(k <= 19998)
k=((k-10999)/1000+1)*10000001+(k-10999)/100%10*1000010+(k-10999)/10%10*100100+(k-10999)%10*11000;
printf("%d\n",k);
}
}


最后一种写法,一开始就把所有的回文数求出来,按从小到大排好序。但是提交Wrong Answer!???
#include<iostream>
#include<algorithm>
using namespace std;

int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}

int a[10000000];

int main()
{
int n, m, i = 0, d1, d2, d3, d4, d5;
for(d1 = 1; d1 <= 9; d1++)
{
a[i++] = d1;
}

for(d1 = 1; d1 <= 9; d1++)
{
a[i++] = d1*10+d1*1;
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
a[i++] = d1*100+d2*10+d1*1;
}
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
a[i++] = d1*1000+d2*100+d2*10+d1*1;
}
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
for(d3 = 0; d3 <= 9; d3++)
{
a[i++]= d1*10000+d2*1000+d3*100+d2*10+d1*1;
}
}
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
for(d3 = 0; d3 <= 9; d3++)
{
a[i++] = d1*100000+d2*10000+d3*1000+d3*100+d2*10+d1*1;
}
}
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
for(d3 = 0; d3 <= 9; d3++)
{
for(d4 = 0; d4 <= 9; d4++)
{
a[i++] = d1*1000000+d2*100000+d3*19999+d4*1000+d3*100+d2*10+d1*1;
}
}
}
}

for(d1 = 1; d1 <= 9; d1++)
{
for(d2 = 0; d2 <= 9; d2++)
{
for(d3 = 0; d3 <= 9; d3++)
{
for(d4 = 0; d4 <= 9; d4++)
{
a[i++] = d1*10000000+d2*1000000+d3*100000+d4*10000+d4*1000+d3*100+d2*10+d1*1;
}
}
}
}

qsort(a,i,sizeof(int),cmp);

scanf("%d", &n);
while(n--)
{
scanf("%d", &m);
printf("%d\n",a[m-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: