Ugly Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 305 Accepted Submission(s): 113
Special Judge
Problem Description
Everyone hates ugly problems.
You are given a positive integer. You must represent that number by sum of palindromic numbers.
A palindromic number is a positive integer such that if you write out that integer as a string in decimal without leading zeros, the string is an palindrome. For example, 1 is a palindromic number and 10 is not.
You are given a positive integer. You must represent that number by sum of palindromic numbers.
A palindromic number is a positive integer such that if you write out that integer as a string in decimal without leading zeros, the string is an palindrome. For example, 1 is a palindromic number and 10 is not.
Input
In the first line of input, there is an integer T denoting the number of test cases.
For each test case, there is only one line describing the given integer s ( 1≤s≤101000 ).
For each test case, there is only one line describing the given integer s ( 1≤s≤101000 ).
Output
For each test case, output “Case #x:” on the first line where x is the number of that test case starting from 1. Then output the number of palindromic numbers you used, n, on one line. n must be no more than 50. en output n lines, each containing one of your palindromic numbers. Their sum must be exactly s.
Sample Input
2 18 1000000000000
Sample Output
Case #1: 2 9 9 Case #2: 2 999999999999 1Hint9 + 9 = 18 999999999999 + 1 = 1000000000000
Source
听说学长长春被这道题卡到了好久我本来还不信,昨天杭电的长春重现赛我们终于理解了学长当时几乎崩溃的心情,模拟题真的恶心!
题目主要是给你一个超大数(最大有一千位),然后让你找到一些回文数(总个数不能超过50个),让这些回文数加起来刚好等于这个超大数。
大概思路参考网上其他人的,还有一些细节是自己慢慢DEBUG出来的。
先用字符串获得超大数z,然后每次z分成两个前后部分,如果前半部分小于后半部分则以z的前半部分作为回文数的回文;如果前半部分大于后半部分,则从中间往前找到第一个不为0的数字,使其减1(不是直接在z上减,而是记录下来再在形成回文数时减1),再把z的前半部分作为回文数的回文。每次生成新的回文数时,z都要减去这个新的回文数。注意前半部分和后半部分的比较是从中间开始往两边比,每次z减去新的回文数是要除去前导0。最后在特判一下z为个位数与及是10、100、1000、10000 ......这种形式。
如果还是迷糊的话,可以看代码,有注释。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
char z[1007], record[55][1007];
bool vis[1007];
bool cmp() /// 判断z的前半部分和后半部分的大小
{
int len = strlen(z), u, v;
if(len&1) u = len/2 + 1;
else u = len/2;
v = len/2 - 1;
while(v >= 0 && u < len) /// 此处从中间往两边判断
{
if(z[u] != z[v]) return z[u] > z[v];
u ++;
v --;
}
return true;
}
void gggg(int key) /// 删去z的前导0
{
for(int i = key; 1; i ++)
{
z[i - key] = z[i];
if(z[i] == '\0') break;
}
}
void drcease(char w[]) /// 模拟减法,用来获得z减去回文数后的值
{
memset( vis, false, sizeof( vis));
int k = strlen(z);
for(int i = k - 1; i >= 0; i --)
{
if(vis[i])
{
if(z[i] == '0')
{
z[i] += 9;
vis[i-1] = true;
}
else z[i] --;
}
if(z[i] >= w[i]) z[i] = z[i] - w[i] + '0';
else
{
z[i] = z[i] + 10 - w[i] + '0';
vis[i-1] = true;
}
}
int x = 0;
while(z[x] == '0') x ++;
if(x) gggg(x);
}
void odd(int len, int k, int fuck) /// 当z前半部分大于后半部分时如何得到回文数
{
int mid = len/2, b, d = 0;
if(fuck) mid --;
for(int i = mid; i >= 0; i --)
if(z[i] != '0')
{
b = i;
break;
}
for(int i = 0; i < b; i ++) record[k][d ++] = z[i];
for(int i = b; i <= len - b - 1; i ++)
{
if(i == b || i == len - b - 1) record[k][d ++] = z[b] - 1;
else record[k][d ++] = '0';
}
for(int i = b - 1; i >= 0; i --) record[k][d ++] = z[i];
record[k][d] = '\0';
// printf("%s\n", record[k]);
drcease(record[k]);
}
bool judge(char w[]) /// 特判一下是否是10、100、1000、10000 ......这种情况
{
if(w[0] != '1') return false;
for(int i = 1; w[i] != '\0'; i ++)
if(w[i] != '0') return false;
return true;
}
int main()
{
int t, u = 0, d;
scanf("%d", &t);
while(t --)
{
scanf("%s", z);
int x = 0;
while(z[x] == '0') x ++;
if(x) gggg(x);
int num = 0;
while(strcmp( z, "\0"))
{
if(strlen(z) == 1) /// 特判一下是否是个位数
{
strcpy( record[++ num], z);
break;
}
else if(judge(z)) /// 10、100、1000、10000 ......这种情况
{
int temp = strlen(z);
num ++;
for(int i = 0; i < temp; i ++)
{
if(i != temp - 1) record[num][i] = '9';
else record[num][i] = '\0';
}
strcpy( record[++ num], "1");
break;
}
if(cmp())
{
num ++; /// 当z后半部分大于前半部分
d = 0;
int g = strlen(z);
for(int i = 0; i < g/2; i ++) record[num][d ++] = z[i];
if(g&1) record[num][d ++] = z[g/2];
for(int i = g/2 - 1; i >= 0; i --) record[num][d ++] = z[i];
record[num][d] = '\0';
drcease(record[num]);
}
else
{
int g = strlen(z);
if(g&1) odd( g, ++ num, 0);
else odd( g, ++ num, 1);
}
}
printf("Case #%d:\n%d\n", ++ u, num);
for(int i = 1; i <= num; i ++)
printf("%s\n", record[i]);
}
return 0;
}