HDU 5920 Ugly Problem

说起这道题, 真是一把辛酸泪.

题意

将一个正整数 \(n(\le 10^{1000})\) 分解成不超过50个回文数的和.

做法

构造.
队友UHC提出的一种构造方法, 写起来比较方便一些, 而且比较巧妙. 可惜我码力太弱, 现场没调出来.
大体的想法是:
将一个数"等"分成两半. 如果长度为奇数可以采取下面两种处理方法之一.

  1. 在开头补0.
  2. 后一半 (低位) 的长度向下取整.

我采取第2种处理方式.

设前一半的长度为\(h_1\), 后一半的长度为 \(h_2\).
然后将前一半长

(写不下去了..., 贴代码...)

Implementation

#include <bits/stdc++.h>
using namespace std;

using num=vector<int>;
using iter=num::iterator;
using riter=num::reverse_iterator;


bool Less(const num &a, const num &b){  // a and b are of same length
    for(auto it1=a.rbegin(), it2=b.rbegin(); it1!=a.rend(); ++it1, ++it2)
        if(*it1 != *it2){
            return *it1 < *it2;
        }
    return false;
}

void borrow(num &a){
        for(int i=a.size()/2; i<a.size(); i++)
            if(a[i]){
                for(--a[i]; i; a[--i]+=9);  //?
                break;
            }
        while(a.size() && *a.rbegin()==0)
            a.pop_back();
}

void split(num &lo, num &hi, const num &a){
    auto mid=a.begin()+a.size()/2;
    lo={a.begin(), mid};
    hi={mid, a.end()};
}

num operator-(num a, num b){    // a and b are of same length && a >= b
    num res;
    for(int i=0; i<a.size(); i++){
        if(a[i]<b[i]){
            a[i]+=10;
            a[i+1]-=1;
        }
        res.push_back(a[i]-b[i]);
    }

    for(; res.size() && *res.rbegin()==0; )
        res.pop_back();

    if(res.size()){ //error-prone
        for(int i=0; i<res.size()-1; i++){
            res[i+1]+=res[i]/10;
            res[i]%=10;
        }

        for(; *res.rbegin()>9; ){
            int t=*res.rbegin();
            *res.rbegin()%=10;
            res.push_back(t/10);
        }
    }

    for(auto x:res){
        assert(x>=0 && x<10);
    }

    return res;
}

vector<num> res;

void out(const num &a){
    for(auto it=a.rbegin(); it!=a.rend(); ++it)
        cout<<*it;
    cout<<endl;
}

void solve(num &a){
    res.clear();
    num lo, hi;
    int ones=0;

    while(a.size()>1){
        // out(a);
        split(lo, hi, a);
        num rhi(hi.rbegin(), hi.rbegin()+lo.size());
        if(Less(lo, rhi)){
            borrow(a);
            ++ones;
            continue;
        }
        a=lo-rhi;
        // There is no advantage to using {} initialization, and one trap,
        // when using auto to get the type determined by the initializer.
        // The trap is that if the initializer is a {}-list, we may not want its
        // type deduced.
        //initializer_list<num> xx={rhi};
        //cout<<typeid(xx).name()<<endl;
        auto tmp=rhi;
        //cout<<typeid(tmp).name()<<endl;
        for(auto &x: hi)
            tmp.push_back(x);
        res.push_back(tmp);
    }

    if(a.size()) res.push_back(a);

    assert(res.size() + ones <= 50);

    printf("%d\n", res.size()+ones);
    for(auto &x: res)
        out(x);
    while(ones--)
        puts("1");
}

char s[1<<10];

int main(){

    // num x, y;
    // in g++:
    // direct-list-intialization of 'auto' requires exactly one element
    // for deduction to 'std::initializer_list', use copy-list-intialization (i.e. add '=' before the '{')
    // auto xx{x, y};

    int T, cas=0;
    num a;
    for(cin>>T; T--; ){
        scanf("%s", s);
        a.clear();
        int n=strlen(s);
        for(int i=n-1; i>=0; --i)
            a.push_back(s[i]-'0');
        printf("Case #%d:\n", ++cas);
        solve(a);
    }
    return 0;
}
posted @ 2016-10-17 15:34  Pat  阅读(175)  评论(0编辑  收藏  举报