题解:LuoguP12381 [蓝桥杯 2023 省 Python B] 保险箱

30 阅读2分钟

题目

链接: P12381.

P12381 [蓝桥杯 2023 省 Python B] 保险箱

题目描述

小蓝有一个保险箱,保险箱上共有 nn 位数字。

小蓝可以任意调整保险箱上的每个数字,每一次操作可以将其中一位增加 11 或减少 11

当某位原本为 9900 时可能会向前(左边)进位/退位,当最高位(左边第一位)上的数字变化时向前的进位或退位忽略。

例如:

  • 0000000000 的第 55 位减 11 变为 9999999999
  • 9999999999 的第 55 位减 11 变为 9999899998
  • 0000000000 的第 44 位减 11 变为 9999099990
  • 9799397993 的第 44 位加 11 变为 9800398003
  • 9990999909 的第 33 位加 11 变为 0000900009

保险箱上一开始有一个数字 xx,小蓝希望把它变成 yy,这样才能打开它,问小蓝最少需要操作的次数。

输入格式

输入的第一行包含一个整数 nn

第二行包含一个 nn 位整数 xx

第三行包含一个 nn 位整数 yy

输出格式

输出一行包含一个整数表示答案。

输入输出样例 #1

输入 #1
5
12349
54321
输出 #1
11

说明/提示

评测用例规模与约定
  • 对于 30%30\% 的评测用例,1n3001 \leq n \leq 300
  • 对于 60%60\% 的评测用例,1n30001 \leq n \leq 3000
  • 对于所有评测用例,1n1051 \leq n \leq 10^5x,yx, y 中仅包含数字 0099,可能有前导零。

思路

这道题就是一道 难度不是特别大的 dp题 对于每一位都有33种可能: 11.进位 22.退位 33.不退不进

建立二维数组dpi,jdp_{i,j}​,其中 ii 表示第几位, jj 表示第几种情况,然后动态规划。 如果上一位(右一位)进位,则本位加一,退位则减一。 接下来判断本位的三种情况,对于每种情况取最小值。 状态转移方程在AC代码里看吧。

AC代码

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

int dp[100005][3], x[100005] = {0}, y[100005] = {0};

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	string xx, yy;
	
    cin >> n >> xx >> yy;
    
    for (int i = 1; i <= n; i++){
	 
		x[i] = xx[n - i] - '0'; 
		y[i] = yy[n - i] - '0';
	}
	
	//进位 
    dp[1][1] = 10 - x[1] + y[1];
    //退位 
    dp[1][2] = 10 - y[1] + x[1];
    //不进不退 
    dp[1][0] = abs(x[1] - y[1]);
    
    for (int i = 2; i <= n; i++){
        // 进位
        dp[i][1] = min({dp[i-1][0] + 10 - x[i] + y[i], dp[i-1][1] + 9 - x[i] + y[i], dp[i-1][2] + 11 - x[i] + y[i]});
        // 退位
        dp[i][2] = min({dp[i-1][0] + 10 - y[i] + x[i], dp[i-1][1] + 11 - y[i] + x[i], dp[i-1][2] + 9 - y[i] + x[i]});
		// 不进不退
        dp[i][0] = min({dp[i-1][0] + abs(x[i] - y[i]), dp[i-1][1] + abs(x[i] + 1 - y[i]), dp[i-1][2] + abs(x[i] - 1 - y[i])});
    }
    cout << min({dp[n][0], dp[n][1], dp[n][2]});
    return 0;
}	

题外话

制作不易,不喜勿喷,点个赞和关注,欢迎评论区讨论,可以提出意见。