AtCoder ABC 155 E - Payment(dp)

题目链接:https://atcoder.jp/contests/abc155/tasks

题意:你去商店买了n(1 <= n <= 1 0 1 , 000 , 000 10^{1,000,000} 101,000,000)元钱的东西东西。然后你和店员都用 1 0 x 10^{x} 10x的货币,问你们两个一共加起来最少要用多少张货币可以把长结清。
比如:36可以的方案:你付3张10块 + 6张1块,店员不用找,共9张
或者你付4张10块,电源找你4张1块,共8张,显然答案为8。

思路:这一题可以考虑dp。从后面开始往前面遍历。
用dp[0][i]表示第i位直接付(s[i] - ‘0’)张 1 0 i 10^{i} 10i的货币,dp[1][i]表示第i位付1张 1 0 i + 1 10^{i+1} 10i+1的货币,店员找10 - (s[i] - ‘0’)张 1 0 i 10^{i} 10i的货币,因为状态转移过程就这两种状态,所以最后输出min(dp[0][0],dp[0][1])就好。具体实现详见代码。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define LL long long

const int maxn = 1e6 + 7;
const LL INF = 1e18;

///dp[0][i] 第i位给s[i] - '0'张10^i张,不用找
///dp[1][i] 第i位给1张10^(i+1)张,找10 - (s[i] - '0')张,共10 - (s[i] - '0'),前一位加1
LL dp[2][maxn];
char s[maxn];

int main() {
    while(~scanf("%s",s + 1)) {
        s[0] = '0';
        int len = strlen(s + 1);
        dp[0][len] = s[len] - '0';
        dp[1][len] = 10 - (s[len] - '0');
        for(int i = len - 1 ; i >= 0 ; i--) {
            dp[0][i] = min(dp[0][i+1] + (s[i] - '0') , dp[1][i+1] + (s[i] - '0' + 1));
            dp[1][i] = min(dp[0][i+1] + 10 - (s[i] - '0') , dp[1][i+1] + 10 - (s[i] - '0' + 1));
            ///dp[1][i+1] + (s[i] - '0' + 1) 中的 "+1" 表示我在第i+1位时给了店员一张10^(s[i+1] - '0')的货币,所以转移到第i位时第i位的值应该+1;
            ///dp[1][i+1] + 10 - (s[i] - '0' + 1) 同理
        }
        printf("%lld\n",min(dp[0][0],dp[1][0]));
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值