zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    HashMap按键排序和按值排序
    LeetCode 91. Decode Ways
    LeetCode 459. Repeated Substring Pattern
    JVM
    LeetCode 385. Mini Parse
    LeetCode 319. Bulb Switcher
    LeetCode 343. Integer Break
    LeetCode 397. Integer Replacement
    LeetCode 3. Longest Substring Without Repeating Characters
    linux-网络数据包抓取-tcpdump
  • 原文地址:https://www.cnblogs.com/mollnn/p/14353241.html
Copyright © 2011-2022 走看看