题目链接

https://codeforces.com/problemset/problem/1409/D

解题思路

卧槽,前天刚去青岛理工参加的青岛市ACM,其中一个题就是把这个题翻译成中文了,当时就听赛场上有人喊原题,***原题啊!

位数太多,不按位存会爆ll。
整体思路:从低位开始修改,且每次修改都是不断加1直至当前位变成0,即发生进位,因为只有发生进位才能使所有位数之和减小。且低位进位完毕后若仍无法使和满足条件,则需要让高位向更高位进位。
每次发生进位都需要修改原数(按位保存在数组中,即修改数组),同时保存对当前这位的修改次数,最后输出每位的操作次数即可。
(可能有同学不明白为什么可以直接保存当前位的修改次数,假设对每一位修改的次数存在数组ans中,假设ans[5~0] = 5,4,3,2,1,0,则直接从5到0输出每一位就是总修改次数,因为每一位默认自带权重,即输出543210就是修改的次数)

看代码注释吧

代码

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

typedef long long ll;
const int N = 25;

int T, s, cnt;
ll n;
int a[N], ans[N];

int main()
{
    cin>>T;
    while(T--) {
        cnt = 0;
        memset(ans, 0, sizeof ans);
        memset(a, 0, sizeof a);
        cin>>n>>s;
        // 获取每一位 
        while(n) {
            a[cnt++] = n%10;
            n/=10;
        }
        // 操作某一位 
        for(int i = 0;i < 19;i ++) {
            int sum = 0;
            // 需先判断 
            for(int j = 0;j < 19;j ++) sum += a[j];
            if(sum <= s) break;

            if(a[i] == 0) continue; // 当当前位为0时,若还对当前位的ans修改则ans变为10,显然不对,这只是反证一下,正推需要自行理解 
            ans[i] = 10-a[i]; // 对当前位的修改次数,其实修改次数为是ans[i]*10^i,但是最后结果要求输出操作次数,我们直接输出ans数组即可,不需要存权重也不需要算出来 
            a[i] = 0;
            int c = 1;
            // 大数加 
            int j;
            for(j = i+1;j < 19;j ++) {
                a[j] = a[j] + c;
                c = a[j]/10;
                a[j] %= 10;
            }
            if(c) a[j] = c;
        }

        int j = 18;
        while(!ans[j] && j > 0) j --;
        for(int i = j;i >=0;i --) cout<<ans[i];
        cout << endl;
    } 
    return 0;
}