D. Decrease the Sum of Digits (思维问题+构造)Codeforces Round #667 (Div. 3)

127 篇文章 3 订阅
20 篇文章 0 订阅

原题链接: http://codeforces.com/contest/1409/problems
在这里插入图片描述
测试样例

input
5
2 1
1 1
500 4
217871987498122 10
100000000000000001 1
output
8
0
500
2128012501878
899999999999999999

题意: 给你一个整数 n n n,你可以进行自增操作,求你最少要进行多少次操作才可以使得 n n n的位数之和小于等于给定的 s s s

解题思路: 这道题看着吓人,但如果理解了就很好处理了(比赛的时候没做出来),我看很多大佬都是用dp写的,但其实没必要,接下来介绍的方法通俗易懂。OK,我们开始进入正题。我们知道,若想让 n n n的第 i i i位之后的数都变为0,又因为 n n n只能自增,那么我们的方法就是一直让 n n n自增使得第 i i i位进1,那么我们经过这个操作发现了什么?我们让第 i i i位进1,抹掉后面的位数。 我们又知道这个题目要求的是 n n n的位数之和要小于等于 s s s,那么如果不小于,我们是不是就要利用那个方法来实现?由于进位是从低位到高位,那么我们必然是要寻找一个需要进位的位置来使得位数之和小于等于s,那么我们遍历自然是从高位到低位。(如果高位的都不满足,那么低位的就更不可能)。 Ok,有了这个思想我们自然是可以去构建进位后的值,再用进位后的值减去原来的值即是我们要增加的次数。具体看代码,我贴了详细注释。注:代码中用到了两个函数to_string()和stoll()函数这两个一个是将数值转换为字符串一个是将字符串转换为数值,这两个函数都需要新版c++版本才支持。我用的是c++17标准

AC代码

/*
*邮箱:unique_powerhouse@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

ll n;
int t,s;
string str;
void solve(){
    str=to_string(n);//将整型数组转化为字符串获取位数之和。
    int cnt=0;//统计位数之和。
    int len=str.size();//获取整型数据的长度,ok,我们开始遍历,判断是哪里需要进位使得条件成立。
    int pos=-1;//pos记录进位点。
    rep(i,0,len-1){
        cnt+=(str[i]-'0');
        if(str[i]=='9'){
            continue;//跳过原因是因为不会将其作为进位点,我如果将后面的补上那么这里自然会进1,故忽略这里。
        }
        if(cnt<s){
            //注意这里是小于,因为我们要留取一个空位来使得进位成功!
            pos=i;//这里记录位置。当不满足时,pos记录的自然是进位点。
        }
    }
    //通过这个操作我们已然确定了进位点。
    //当然我们这里需要判断一些情况。
    if(cnt<=s){
        //如果位数之和符合,那么我们必然不用进行任何操作。
        cout<<0<<endl;
    }
    else if(pos==-1){
        //那么说明进位点在第一个的前面,那么我们自然要构建下面式子。
        str="1";
        rep(i,0,len-1){
            str+="0";
        }
        cout<<stoll(str)-n<<endl;//这里stoll函数是将字符串转为为整型数据。
    }
    else{
        //那么这个时候我们是同样的方法,让进位点进1,之后的清0即可。
        str[pos]++;//进位,之后的全部抹0.
        rep(i,pos+1,len-1)
            str[i]='0';
        cout<<stoll(str)-n<<endl;
    }
}
int main(){
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>t){
        while(t--){
            cin>>n>>s;
            solve();
        }
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeZephyr

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值