2114: 完美数 - #include <Seter> - using namespace Orz;
2114: 完美数
http://www.zybbs.org/JudgeOnline/problem.php?id=2114
| RunID | User | Problem | Result | Memory | Time | Language | Code Length | Submit Time |
| 185268 | Seter | 2114 | Accepted | 776 kb | 20 ms | C/Edit | 998 B | 2012-01-02 19:48:39 |
今天又学到新东西了——如何求比x大的第n个回文数?答案就是,给每个回文数从小到大用自然数连续编号。
我们假设0的编号是1,按照回文数,回文节(前一半位数),编号列表:
| 0 | 0 | 1=0+1 |
| 9 | 9 | 10=9+1 |
| 99 | 9 | 19=9+10 |
| 111 | 11 | 21=11+10 |
| 999 | 99 | 109=99+10 |
| 1001 | 10 | 110=10+100 |
| 9999 | 99 | 199=99+100 |
| 12221 | 122 | 222=122+100 |
观察到,偶数位数的回文数,编号就是在回文节最前面加个1。奇数位数的回文数,编号就是回文节最前面的一位加上1。
再举个例子:abcba->(1+a)bc,abccba->1abc。
那么如何解码呢?首先要确定编码对应的回文数位数的奇偶性。如果是偶数位,那么必定以1开头,第二位存在且不是0,否则必是奇数位(奇数位要么第一位不是1,如果是1说明原回文数第一位是9,且进了一位,那么第二位必定是0。相反,偶数位数的回文数的编码第二位必定不是0)。
确定奇偶性后只要正着输一遍反着输一遍就可以了……
忘说了囧……由于这个编码是只针对回文数的,所以还要先找到x的下一个回文数……具体可以先用x的前一半位构造出一个回文数,如果大于x则是此回文数的后n-1个,否则是此回文数的后n个。(我沙茶就是因为这个忘了2Y……)
#include <stdio.h>
#include <string.h>
int t;
char x[10010],n[10010];
main(){
int i,l,s;_Bool v;
for(scanf("%d\n",&t);t--;){
gets(x);gets(n);l=(s=strlen(x))+1>>1;v=0;
for(i=l;i--;)if(x[i]>x[s-1-i]){v=1;break;}else if(x[i]!=x[s-1-i])break;
for(i=l;i--;x[10010-l+i]=x[i]-48);
l=10009-l;memset(x,0,l+1);
if(s&1){if(10==++x[l+1])x[l+1]=0,x[l--]=1;}
else x[l--]=1;
for(i=s=strlen(n);i--;)for(x[l=10010+i-s]+=n[i]-48;x[l]>=10;){
x[l]-=10;
x[--l]++;
}if(v)for(x[i=10009]--;x[i]==-1;x[--i]--)x[i]=9;
for(i=-1;!x[++i];);
if(i==10009){
putchar(x[i]+47);
putchar('\n');
continue;
}if(x[i]==1&&x[i+1]){
for(s=i;++i!=10010;)putchar(x[i]+48);
for(;--i!=s;)putchar(x[i]+48);
putchar('\n');continue;
}if(x[i]==1)x[i]=0,x[i+1]=9;
else x[i--]--;
for(s=i;++i!=10010;)putchar(x[i]+48);
for(--i;--i!=s;)putchar(x[i]+48);
putchar('\n');
}return 0;
}
By Seter
评论 (0)