题目链接
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; }