[CF988E] Divisibility by 25

[CF988E] Divisibility by 25 - 贪心

Description

给出一个从 1 到 10^18 的整数 n,不包含前导零。在一次移动中,可以交换任意两个相邻数字,使得结果数字不包含前导零。获取可被 25 整除的数字所需的最小移动次数是多少?

Solution

就那么几种情况

  • 把 5 冒泡到最后,把 2 冒泡到倒数第二位
  • 把 5 冒泡到最后,把 7 冒泡到倒数第二位
  • 把 0 冒泡到最后,把 5 冒泡到倒数第二位
  • 把 0 冒泡到最后,把另一个 0 冒泡到倒数第二位

我们可以先尝试性地做一下,如果换完以后有前导零,那么再强行找一个最左边的非零数字换到前面来,如果换完以后炸了那么这种情况就无效

可以证明先把非零数字换到前面,和先把有效数字换到后面,得到的答案是一样的

找到最靠右的两个我们要找的数字,下标为 i,j,假设我们的目标是把 j 换到最后,i 换到倒数第二个位置

如果只有 i,j 两个数字,皆大欢喜(这时 i,j 不可能都是 0)

如果除了 i,j 外的第一个数字是 0,我们要找到第一个非零的数字,如果找到了记录它的下标 k,如果没找到直接结束

现在我们是把 j 换到最后,i 换到倒数第二个位置,如果有的话,把 k 换到第一个位置

这个过程中,会出现的基础贡献为 n-j+n-1-i+k-1

考虑相互作用导致的附加贡献,如果 (k>i) 则附加贡献,如果 (k>j) 则附加贡献,如果 (i>j) 则附加贡献

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

#define int long long

int solve(string s, int ii, int jj)
{
    int n = s.length();
    int i = -1, j = -1, k = -1;
    for (int t = s.length() - 1; t >= 0; t--)
        if (s[t] == '0' + jj)
        {
            j = t;
            break;
        }
    for (int t = s.length() - 1; t >= 0; t--)
        if (s[t] == '0' + ii && t != j)
        {
            i = t;
            break;
        }
    for (int t = 0; t < s.length(); t++)
        if (s[t] != '0' && t != i && t != j)
        {
            k = t;
            break;
        }
    ++i;
    ++j;
    ++k;
    if (i == 0 || j == 0)
    {
        return 1e9;
    }
    if (s.length() > 2)
    {
        int pin = 1;
        if (pin == i)
            ++pin;
        if (pin == j)
            ++pin;
        if (pin == i)
            ++pin;
        if (pin == j)
            ++pin;
        --pin;
        if (pin < s.length() && s[pin] == '0')
        {
            if (k)
            {
                int ans = n - j + n - 1 - i + k - 1 - (k > i) - (k > j) + (i > j);
                return ans;
            }
            else
            {
                return 1e9;
            }
        }
    }
    int ans = 0;
    ans = n - j + n - 1 - i + (i > j);
    return ans;
}

signed main()
{
    ios::sync_with_stdio(false);

    int ans = 1e9;
    string s;
    cin >> s;
    ans = min(ans, solve(s, 0, 0));
    ans = min(ans, solve(s, 2, 5));
    ans = min(ans, solve(s, 5, 0));
    ans = min(ans, solve(s, 7, 5));
    if (ans < 1e8)
        cout << ans << endl;
    else
        cout << -1 << endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14353241.html