1 条题解

  • 0
    @ 2026-10-31 17:58:10

    思路

    记输入中加号个数为 kk,则最终要把所有数字字符分成 k+1k+1 个正整数相加。

    最优性分析

    1. 长度必须尽量均匀。 设某个数的长度比另一个数至少多 22。把较长数最高位的数字挪到较短数的最高位:它占的位权从 10L1−110^{L_1-1} 变成 10L210^{L_2},其余位权不变。因为 L2≤L1−2L_2\le L_1-2,有 10L2<10L1−110^{L_2}<10^{L_1-1},而所有数字都是正数,总和严格减小。所以最优解中任意两个数的长度差不超过 11。
    2. 长度固定后是重排不等式。 总和 =∑d⋅10w=\sum d\cdot 10^{w},对每个数字是线性的。长度分配固定后,所有位权 10w10^w 的集合固定;由重排不等式,把最小的数字配最大的位权(等价于每个数内部升序、且整体按位权从高到低依次放最小的数字)总和最小。
    3. 轮询正是这个配对。 把数字升序排序,第 jj 轮把第 jj 批 p=k+1p=k+1 个数字分别填到 pp 个数当前未填的最高位,正好实现了"位权降序配数字升序",同时保证各数长度差不超过 11。

    贪心构造

    1. 将所有数字字符按升序排序(加号字符 ASCII 比数字小,排序后自然排在最前面,直接跳过即可);
    2. 按轮询(round-robin)的方式分配:第 cnt 个数字放进第 cnt mod p 个数,等价于第 jj 轮把第 jj 批 pp 个数字依次填到 pp 个数当前未填的最高位;
    3. 最后把这 k+1k+1 个数按位相加得到答案(用结构体实现大数加法,注意处理进位)。

    复杂度:排序 O(nlog⁡n)O(n\log n),分配与逐位相加 O(n)O(n),空间 O(n)O(n)。

    代码

    #include<bits/stdc++.h>
    #define int long long
    #define str string
    #define all(x) x.begin(),x.end()
    #define pb push_back
    using namespace std;
    
    // 大整数结构体:a 按高位到低位存每一位数字
    struct node{
        vector<int>a;
        int len;
        node(): a(), len(0) {}
    
        // 在末尾追加一位数字
        void add(int num){
            a.pb(num);
            len++;
        }
    
        // 重载加法运算符,实现大数相加
        node operator+(const node&x)const{
            auto a1 = a, a2 = x.a;   // 拷贝一份,避免修改原对象
            reverse(all(a1));        // 翻转成低位在前,方便从个位开始加
            reverse(all(a2));
            node res;
            int plus = 0;            // 进位
            int mx = max(len, x.len);
    
            for(int i=0;i<mx;i++){
    
                int n1 = i<len? a1[i]:0;      // 超出长度的位补 0
                int n2 = i<x.len? a2[i]:0;
    
                int t = (n1+n2+plus) % 10;    // 本位结果
                plus = (n1+n2+plus) / 10;     // 向高位的进位
    
                res.a.pb(t);
    
            }
    
            if(plus){res.a.pb(plus);}         // 最高位还有进位就再补一位
            res.len = res.a.size();
            reverse(all(res.a));              // 翻回高位在前
            return res;
        }
    
        // 打印大数
        void pr(){
            for(int i=0;i<len;i++){
                cout<<a[i];
            }
            cout<<endl;
        }
    };
    
    void go(){
        str s;cin>>s;
        int cn = count(all(s), '+');   // 加号个数,结果要分成 cn+1 个数
    
        vector<node>a(cn+1);
        int p = cn+1;
        int cnt = 0;
    
        sort(all(s));                  // 数字升序排列
    
        for(char c:s){
            if(c=='+')continue;        // 跳过加号
    
            int dec = c-'0';
            a[cnt%p].add(dec);         // 轮询分配:第 cnt 个数字交给第 cnt%p 个数
            cnt++;
        }
    
        // 把 k+1 个数全部相加
        node ans;
        for(int i=0;i<=cn;i++){
            ans = ans+a[i];
        }
    
        ans.pr();
    
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int _=1;
        // 本题只有一组数据,不需要读入测试组数
        while(_--){
            go();
        }
        return 0;
    }
    
    • 1

    信息

    ID
    19
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者