1.题意:给你一个数字N,让你把它拆成n(n<=50)个回文数字的和,并输出这些回文数字(N<=10^1000)
2.分析:
(1)对于一个数字,我们先找尽可能接近他的会回文数字,然后减去。但是这个回文数字太难找了,怎么办?我们可以把当前数字前半部分对称到后面去,比如123 其对应的会回文数字为121。但是这里就面临一个问题:120对应的121比120大,所以我们这里可以把12减1再对称为111就可以了
(2)为了防止冗杂的判断,我们为了保证回文 + 小于原数字,直接取前一半减1在对称。如10000->取前一半100->减99->对称9999 不断取剩余数字的回文,知道原数字减为0即可。
(3)特判:13取前一半减1对称后变成了00,也就是如果减1后变为了0,这样的只有1,所以保持1不动即可。还有10这个数字,保持不动对称为11,减1为00,都不符合,所以特判为 9 + 1;
3.代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 7;
char num[maxn],num2[maxn],another[maxn],sub[maxn];
char ans[51][maxn];
char one[2] = "1";
bool judge(char *s){//判断当前数字是否为回文数字
int lens = strlen(s);
for(int i = 0;i<lens/2;i++){
if(s[i]!=s[lens - i - 1]){
return false;
}
}
return true;
}
void Decrease(char *s1,char *s2){//大数减法,s1 - s2并把结果赋值给s1去掉前导0
int len1 = strlen(s1);
int len2 = strlen(s2);
int i = len1-1;
int j = len2-1;
int flag = 0;
while(i>=0&&j>=0){
if(s1[i] - '0'>=flag){
s1[i] = s1[i] - flag;
flag = 0;
}
else{
s1[i] = s1[i] + 10 - flag;
flag = 1;
}
if(s1[i]>=s2[j]){s1[i] = s1[i] -s2[j] + '0';}
else{
s1[i] = s1[i] + 10 - s2[j] + '0';
flag = 1;
}
i--;
j--;
}
while(flag&&i>=0){
if(s1[i] - '0'>=flag){
s1[i] = s1[i] - flag;
flag = 0;
}
else{
s1[i] = s1[i] + 10 - flag;
flag = 1;
}
i--;
}
//cout<<s1<<endl;
int l = 0;
bool flagd = false;
memset(another,0,sizeof(another));
for(int k = 0;k<len1;k++){//去掉前导0
if(s1[k]=='0'&&!flagd)continue;
else if(s1[k]!='0'&&!flagd){
flagd = true;
another[l++] = s1[k];
}
else if(flagd){
another[l++] = s1[k];
}
}
if(!l){another[l] = '0';l++;}//减法完为0
another[l] = '\0';
strcpy(s1,another);//复制
}
void palindromic(char *s1,char *s2){//取s1的回文串s2
int len1 = strlen(s1);
if(len1==2&&s1[0]=='1'&&s1[1]=='0'){//特判
s2[0] = '9';
s2[1] = '\0';
return;
}
int len2 = (len1&1)?len1/2 + 1:len1/2;
for(int i = 0;i<len2;i++){//取前一半
s2[i] = s1[i];
}
s2[len2] = '\0';
Decrease(s2,one);//减1
if(s2[0]=='0'){//判断1
s2[0] = '1';
}
for(int i = len1-1,j = 0;j<i;i--,j++){
s2[i] = s2[j];//对称
}
s2[len1] = '\0';
}
int main()
{
int T;
scanf("%d",&T);
int t = 0;
while(T--){
scanf("%s",num);
t++;
int le = 0;
while(num[0]!='0'&&le<=50){
le++;
//cout<<"num:"<<num<<endl;
if(judge(num)){//当前为回文,直接结束
strcpy(ans[le++],num);
break;
}
memset(sub,0,sizeof(sub));
palindromic(num,sub);//取回文数字sub
//cout<<"sub:"<<sub<<endl;
strcpy(ans[le++],sub);//保存结果sub
Decrease(num,sub);//num - sub
}
printf("Case #%d:\n%d\n",t,le);
for(int i = 0;i<le;i++){
printf("%s\n",ans[i]);
}
}
return 0;
}