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;
    }
    
  • 相关阅读:
    【NumPy】 之常见运算(np.around、np.floor、np.ceil、np.where)(转)
    python3中collections模块(转)
    numpy.random模块用法小结
    生成模型和判别模型(《统计学习方法》截图)
    linux(Ubuntu)下机器学习/深度学习环境配置
    sklearn中predict_proba的用法例子(转)
    机器学习案例实战之信用卡欺诈检测——收获的技术
    分析长期治疗数据显示TNF拮抗剂似乎并未增加严重感染和肿瘤发生风险
    超声在鉴别诊断RA与PsA中的应用价值
    结合超声计数炎症关节的改良版DAS28的临床应用
  • 原文地址:https://www.cnblogs.com/mollnn/p/14353241.html
Copyright © 2011-2022 走看看