题意
给定n位字符串,可以对每位进行+1/-1的操作,同时产生相应的进位/退位,9999+1将会变为0000,求变成目标串最少的操作次数
思路
这道题一开始还以为是ICPC沈阳的一道题Luggage Lock,但是那道题可以对连续几位同时进行+1/-1,本题只能对一位处理且会产生进位/退位。
正解为状态机dp,表示当前在第位,将要通过方式所需要的最少操作次数,其中方式分别表示:
状态转移方程式如下:
由于某一位的改变只会对他的前面一位产生影响,所以需要倒着进行遍历
不需要考虑第一位的改变对于最后一位的影响,显然第一位进位不会更优
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include<bits/stdc++.h> #define int long long using namespace std; #define endl '\n' const int N=1e5+10; typedef pair<int,int>pp; int char_to_num(char ch){ return ch-'0'; } void solve() { int n; cin>>n; string s,t; cin>>s>>t; vector<vector<int>>f(n+2,vector<int>(3)); int a=char_to_num(s[n-1]),b=char_to_num(t[n-1]);
f[n-1][0]=fabs(a-b); f[n-1][1]=a+10-b; f[n-1][2]=b+10-a; for(int i=n-2;i>=0;--i){ int a=char_to_num(s[i]),b=char_to_num(t[i]); f[i][0]=min({f[i+1][0]+fabs(a-b),f[i+1][1]+fabs(a-1-b),f[i+1][2]+fabs(a+1-b)}); f[i][1]=min({f[i+1][0]+a+10-b,f[i+1][1]+a-1+10-b,f[i+1][2]+a+1+10-b}); f[i][2]=min({f[i+1][0]+b+10-a,f[i+1][1]+b+10-(a-1),f[i+1][2]+b+10-(a+1)}); } cout<<min({f[0][0],f[0][1],f[0][2]})<<endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T=1; while(T--) solve(); return 0; }
|