Ugly Problem(hdu 5920 && 2016ICPC长春现场赛模拟题)

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.
 

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 ( 1s101000 ).
 

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 1
Hint
9 + 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值