-
题意
给你一个整数n(1≤n≤1018,不含前导零),你能够将任意两个相邻位置上的数互换位置,每交换一次算一步,每一次交换过后的数不能有前导零。现在要求以最少的步数使这个数变为25的倍数,输出这个步数。 -
思路:看上面大佬链接
-
我的理解:
举例:
n = 1153246
目的明显,即将‘2’‘5’移到最右边。(第一次移动‘5’,第二次移动‘2’)观察发现,其实无论‘2’和‘5’谁在前谁在后,每次移动都是为了移动到‘6’后面的第一位。(也即计算‘2’和‘5’相对‘6’的位置,但注意,计算‘2’与‘6’的相对位置前,需要将‘5’删掉,因为‘5’已经移到右边了)
上述大佬的题解中,之所以删掉‘5’,是为了避免将‘5’移动到‘6’的右边后,计算‘2’与‘6’的相对位置时,由于’5‘的存在而造成误差(’2‘在’5‘的左边时,’5‘占一位,这里好像与上面链接中的矛盾,我觉得是大佬的错了。。。)
最后对前导零的情况作处理,若剩下的都为0(删除那两个字符后剩下的串),则这种情况不可取,返回inf即可,否则就将第一个不为0的移到最左边。
最后献上我的代码:
#include<cstdio>
#include<queue>
#include<cstdlib>
#include<string.h>
#include<string>
#include<iostream>
#include<cmath>
#include<map>
#include<algorithm>
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
#define ft first
#define sd second
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ll long long int
#define mt(a,b) memset(a, b, sizeof a)
const int inf = 0x3f3f3f3f;
const int INF = 0x7fffffff;
using namespace std;
const int N = 2e5, M = 1e6;
int judge(char a, char b, string s)
{
int len = s.size();
int idx2 = s.rfind(b);
if (idx2 == -1) return inf;
s.erase(idx2, 1);
int idx1 = s.rfind(a);
if (idx1 == -1) return inf;
s.erase(idx1, 1);
int cnt = 0;
while (s[cnt] == '0') cnt++;
if (cnt && cnt + 2 == len) return inf;//删除a和b后剩字符下全为0 ,注意要判断一下是否存在前导零
//cout << cnt << "----\n";
//cout << a << b << " " << cnt + len - 1 - idx2 + len - 2 - idx1 << endl;
return cnt + (len - 1 - idx2) + (len - 2 - idx1);//len - 1为b未删掉前字符串最右边的索引,len - 2 为删掉后最右边的索引
}
int main()
{
IOS;
string s;
cin >> s;
int ans = inf;
ans = min(judge('2', '5', s), ans);
ans = min(judge('0', '0', s), ans);
ans = min(judge('7', '5', s), ans);
ans = min(judge('5', '0', s), ans);
if (ans == inf) cout << -1 << endl;
else cout << ans << endl;
return 0;
}
end