1 条题解

  • 0
    @ 2025-8-24 23:06:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ddxrS_loves_zxr
    一个诗意的个性签名

    搬运于2025-08-24 23:06:54,当前版本为作者最后更新于2025-02-05 01:12:44,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    先让我们考虑一个贪心。

    想要得到 11,就只能是通过将 1000100\dots 0 循环右移一次,而得到 1000100\dots 0 只能是将 999+199\dots 9+1 或者原本的 nn 就是这个样子。

    那么对于给定的 nn,若其最低位 0<c<90<c<9,那么增加 9c9-c 次,然后位移;若 c=0c=0 就直接位移。

    执行上述操作直到 nn 全部变为 99,然后再花费两次变成 11

    这个贪心可以通过子任务 1,21,2

    这个贪心显然是错的,比如当 n=9991062 个89n=\underbrace{99\dots 9}_{10^6-2\text{ 个}}89 时,进行 1010 次增加操作要优于 106110^6-1 次位移操作。

    问题在于我们并不能够确定位移操作的执行次数,在某些情况下使用增加操作去代替位移操作可能是更优的。

    假设要进行 kk 次位移操作,我们将 nn 分成两段:一段包含前 kk 个非零数位以及在其之后接上的 00;另一段包含剩下的数位。分别记作前缀 pp 和后缀 ss

    例如在 n=120030005607n=120030005607k=3k=3p=12003000,s=5607p=12003000,s=5607

    我们的策略是,先对后缀 ss 进行增加操作,直到后缀全变成 99,需要做 999s 的长度个s\underbrace{99\dots 9}_{s\text{ 的长度个}}-s 次。

    之后再按照最开始的贪心来处理前缀 pp,这部分要 k+9cik+\sum9-c_i 次。

    同时先进行位移操作再将后缀 ss 全部变为 99 是不优的,因为你进行位移操作过后,将 ss 变为 99 的代价会增加 1010 倍。

    nn 的长度为 mm,那么时间复杂度为 O(m2)O(m^2)

    可以发现,对后缀 ss 进行很多次增加操作是不会优于直接贪心的。

    贪心最多只会耗费 10710^7 次操作,因此我们只需要枚举使得后缀 ss 增加的次数不超过 10710^7 次的情况。

    tt 表示 nn 中非零数位的数量,那么只需要 t7ktt-7\le k\le t

    还存在一种情况就是存在一种后缀形如 999ABCDEFG99\dots 9ABCDEFG,这种后缀的增加次数也不会超过 10710^7

    所以总共需要考虑的情况只有 O(1)O(1) 种,时间复杂度 O(m)O(m)

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const int N = 1e6 + 5;
    int n, k;
    string s;
    ll solve(int r) {
        ll sum = r, i, j, tot = 0, tmp = 0;
        for(i = 1, j = 0; i <= n && j < r; i++) if(s[i] > '0') sum += '9' - s[i], j++;
        while(i <= n && s[i] == '0') i++;
        while(i <= n && s[i] == '9') i++;
        if(n - i + 1 > 7) return 0x3f3f3f3f3f3f3f3f;
        for(; i <= n; i++) tot = tot * 10 + 9, tmp = tmp * 10 + s[i] - '0';
        return sum + tot - tmp;
    }
    int main() {
    #ifdef ddxrS
        freopen("sample.in", "r", stdin);
        freopen("sample.out", "w", stdout);
    #endif
        ios::sync_with_stdio(0);
        cin.tie(0), cout.tie(0);
        cin>>s; n = s.length(), s = '#' + s;
        for(int i = 1; i <= n; i++) k += (s[i] != '0');
        if(k == 1 && s[1] == '1' && n == 1) return cout<<0<<'\n', 0;
        if(k == 1 && s[1] == '1') return cout<<1<<'\n', 0;
        ll ans = 0x3f3f3f3f3f3f3f3f, lst = n;
        for(int i = n - 7; i >= 0; i--) if(s[i] != '9') {lst = i; break;} 
        for(int i = max(0, k - 7); i <= k; i++) ans = min(ans, solve(i));
        cout<<min(ans, solve(lst)) + 2<<'\n';
        return 0;
    }
    
    • 1

    信息

    ID
    11076
    时间
    1000ms
    内存
    500MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者