POJ 2402 Palindrome Numbers(LA 2889) 回文数

POJ:http://poj.org/problem?id=2402

LA:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=890

题目大意:

回文数从小到大排列为:1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, ……输入n,(1<=n<=2*10^9),求第n小的回文数。

思路:

我们先统计一下i个数字组成的回文数的个数,cnt[i]=cnt[i-1]+9*mypow(10,p);

然后第n个回文数只要看看他是几位的就可以了。

如n=520,求出他需要5位,而1~4位所有的回文数个数(总的)为198,故k=520-198=322

找100为三位的基准,(为什么是3位? 长度为5的一般,向上取整。。为什么是100,三位最小哇)

100+k-1=100+321=421

所以一半求出来了,另一半呢(T T不是指对象)

根据对称性,可得42124


版本一:

#include<cstdio>
#include<cstring>
#include<cmath>
typedef long long LL;
const int MAXN=20;
LL cnt[MAXN]={0};
char ans[MAXN];
LL mypow(LL x,LL p)  
{  
	long long res=1;  
	while(p--) res*=x;  
	return res;   
}   
int main()
{
	for(int i=1;i<MAXN;i++)
	{
		LL p=(i+1)/2-1;
		cnt[i]=cnt[i-1]+9*mypow(10,p);
	}

	int n;
	while(~scanf("%d",&n),n)
	{
		int k,num;
		for(int i=1;i<MAXN;i++)
		{
			if(n <= cnt[i])    //万恶的等于号!!!!
			{
				k=n-cnt[i-1];//还需要的个数
				num=i;  //位数
				break;
			}
		}
		int len=num;
		num=(num+1)/2;
		LL x=mypow(10,num-1)+k-1;

		printf("%lld",x);
		if(len %2!=0) x/=10;
		while(x) 
		{
			printf("%lld",x%10);
			x/=10;
		}
		printf("\n");
	}
	return 0;
}

版本二:(请选择G++提交,因为pow函数要double而我是long long ,c++会说CP)

#include<cstdio>
#include<cmath>
#include<cstring>
typedef long long LL;
const int MAXN=22;
LL cnt[MAXN]={0};
char ans[MAXN];
int main()
{
	for(int i=1;i<MAXN;i++)
	{
		LL p=(i+1)/2-1;
		cnt[i]=cnt[i-1]+9*pow(10,p);
	}

	int n;
	while(~scanf("%d",&n),n)
	{
		int k,num;
		for(int i=1;i<MAXN;i++)
		{
			if(n <= cnt[i])
			{
				k=n-cnt[i-1];
				num=i;
				break;
			}
		}

		LL x=pow(10,(num+1)/2-1);
		x+=k-1;
		sprintf(ans,"%lld",x);
		int len=strlen(ans);
		for(int i=0;i<len;i++)
			printf("%c",ans[i]);
		if(num &&num % 2==0)
			printf("%c",ans[len-1]);
		for(int i=len-2;i>=0;i--)
			printf("%c",ans[i]);
		printf("\n");
	}
	return 0;
}


posted @ 2014-02-04 23:49  hr_whisper  阅读(199)  评论(0编辑  收藏  举报