zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 90 题解

    有几年没有打 CF 了,最近特别想做一下算法题怀念一下。

    A. Donut Shops

    背景:商店 X 卖 1 份油炸圈饼 a 元,商店 Y 卖 b 份油炸圈饼 c元(只能买 b 的倍数份这样批发)

    问题:在 X 商店买多少份价格严格小于 Y 商店?在 Y 商店买多少份价格严格小于 X 商店?有多种可行解输出任何一个,否则输出 -1.

    思路:在 X 商店买肯定是单买 1 份最划算,在 Y 商店肯定直接批发 b 份最划算,然后计算下两边价格就是了

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
     
    void run() {
        ll a, b, c;
        cin >> a >> b >> c;
        if (a < c) {
            cout << 1 << " ";
        } else {
            cout << -1 << " ";
        }
        if (c < a * b) {
            cout << b << "
    ";
        } else {
            cout << -1 << "
    ";
        }
    }
     
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        std::setvbuf(stdout, nullptr, _IOFBF, BUFSIZ);
        int T;
        cin >> T;
        while (T-- > 0) {
            run();
        }
    }

    B. 01 Game

    背景:有一个 0 或 1 组成的字符串,每次可以拿走其中的 01 或者 10,A 和 B 轮流拿,A先拿,直到拿不动了就输了。

    问题:A 和 B 都按照最优方案去哪,A 是否能赢?

    思路:直接贪心去拿串中的第一个 01 或者 10;可以分情况讨论一下,这种策略不会比其他策略差;然后记忆化搜索一下输出结果就好了

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    
    unordered_map<string, int> cache;
    
    /**
     * 返回 2 为必败态,返回 1 为必赢态
     */
    int calc(string &s) {
        int &ans = cache[s];
        if (ans > 0) return ans;
        if (s.empty() || s.find('0') == string::npos || s.find('1') == string::npos) {
            return ans = 2;
        }
        ans = 2;
        for (int i = 1; i < s.length(); ++i) {
            if (s[i] != s[i - 1]) {
                string cur = s.substr(0, i - 1) + s.substr(i + 1, s.length());
                if (calc(cur) == 2) ans = 1;
                break;
            }
        }
        return ans;
    }
    
    void run() {
        string s;
        cin >> s;
        cout << (calc(s) == 1 ? "DA" : "NET") << "
    ";
    }
    
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        std::setvbuf(stdout, nullptr, _IOFBF, BUFSIZ);
        int T;
        cin >> T;
        while (T-- > 0) {
            run();
        }
    }

    C. Pluses and Minuses

    背景:给你一个函数,参数为一个只有 + 或者 - 组成的字符串,问你函数执行结果 res 是啥?

    分析:这个函数转换下意思,即 初始值为0,然后按字符串不断执行 +1 或 -1,直到变成负数执行了多少次。然后初始值变为 1 2 ...,直到可以全部把字符串执行下来。问你总共执行了多少次。

    思路:则可以计算出到每一个指令 (+1 or -1) 时所需的最小的初始值,可以看到这个所需初始值是递增的。然后遍历初始值,二分找到最远能执行到哪个指令,累加即可。

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
     
    void run() {
        string s;
        cin >> s;
        int cur = 0, need = 0;
        vector<int> v(s.length());
        for (int i = 0; i < s.length(); ++i) {
            if (s[i] == '-') {
                cur -= 1;
            } else {
                cur += 1;
            }
            if (cur < 0) {
                need = max(need, -cur);
            }
            v[i] = need;
        }
        ll ans = 0;
        for (int i = 0; i <= v.back(); ++i) {
            int pos = static_cast<int>(upper_bound(v.begin(), v.end(), i) - v.begin()) + 1;
            ans += min(pos, (int) s.length());
        }
        cout << ans << "
    ";
    }
     
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        std::setvbuf(stdout, nullptr, _IOFBF, BUFSIZ);
        int T;
        cin >> T;
        while (T-- > 0) {
            run();
        }
    }

    D. Maximum Sum on Even Positions

    背景:给你一个数组,你可以 reverse 其中的任意一段一次,问你这样操作后的“数组中偶数下标对应的数之和的最大值”是多少

    思路:

    翻转一段肯定是翻转偶数长度,否则没有意义了。

    比如你翻转  1 7 3 4 变成 4 3 7 1 ,获得的收益 = (7-1) + (4-3),即奇数位置 - 偶数位置,应该使得这个值最大。

    这样两两一组去看,就能把问题转化为最大区间和的问题,利用“当前值 - 最小前缀”和的做法可以优化为  O(N)  求解。

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
     
    void run() {
        int N;
        cin >> N;
        vector<ll> v(N);
        ll ss = 0;
        for (int i = 0; i < N; ++i) {
            cin >> v[i];
            if (i % 2 == 0) ss += v[i];
        }
        ll best = ss;
        ll sum = 0, preMin = 0;
        for (int i = 0; i + 1 < N; i += 2) {
            sum += v[i + 1] - v[i];
            best = max(best, ss + sum - preMin);
            preMin = min(preMin, sum);
        }
        sum = 0, preMin = 0;
        for (int i = 1; i + 1 < N; i += 2) {
            sum += v[i] - v[i + 1];
            best = max(best, ss + sum - preMin);
            preMin = min(preMin, sum);
        }
        cout << best << "
    ";
    }
     
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        std::setvbuf(stdout, nullptr, _IOFBF, BUFSIZ);
        int T;
        cin >> T;
        while (T-- > 0) {
            run();
        }
    }

    E. Sum of Digits

    背景:函数 f(x) 的作用是求10进制数字 x 每位的和,给你一个目标值 n 和 k,让你找一个最小的 x 使得 f(x) + f(x+1) + ... + f(x + k)  = n.

    思路:

    先看 k = 0 的情况,即找到最小的 x 使得 f(x) = n

    发现 f(19998) = f(9999) = 36,所以 5 位数凑出 36 不如用每位数都为 9 的 4 位数凑。f(59990) = f(49991) = 32,同样都是 5 位数凑 32,应该尽可能让高位小。

    因此我们应该有一部分数,而不选择其比他大的数,能够凑出那个 n 来,这些数的特征为:高位为 1-9,低位为 0-9,且中间全是 9,我们把它枚举出来(数量应该不会很多)。

    考虑 k 为 1-9 的情况,原来我们枚举的 x 的个位数 0-9 可能不够用了(可能 x + k 发生进位,前面的 9 进没了,加起来就不够了),所以我们枚举 后两位为 80-99,这样就不会进位就够用了。

    把这样的可能的 x 都枚举出来,可以发现数量不多,然后从小到大排序后,找到第一个满足 f(x) = n 的即可(暴力)。

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
     
    vector<ll> base;
     
    void init() {
        for (int i = 0; i <= 999; ++i) { // 三位数以下手动处理
            base.push_back(i);
        }
        for (int mc = 1; mc <= 15; ++mc) { // 中间9的个数
            for (int i = 1; i <= 9; ++i) {  // 首位数
                for (int j = 80; j <= 99; ++j) { // 末尾两位数
                    string cur = to_string(i) + string(mc, '9') + to_string(j);
                    base.push_back(stoll(cur));
                }
            }
        }
        sort(base.begin(), base.end());
    }
     
    ll f(ll x) {
        ll ret = 0;
        while (x > 0) {
            ret += x % 10;
            x /= 10;
        }
        return ret;
    }
     
    void run() {
        ll N, K;
        cin >> N >> K;
        ll found = -1;
        for (ll b : base) {
            ll sum = 0;
            for (int j = 0; j <= K; ++j) {
                sum += f(b + j);
            }
            if (sum == N) {
                found = b;
                break;
            }
        }
        cout << found << endl;
    }
     
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        std::setvbuf(stdout, nullptr, _IOFBF, BUFSIZ);
        init();
        int T;
        cin >> T;
        while (T-- > 0) {
            run();
        }
    }
  • 相关阅读:
    MusicXML 3.0 (7) 连线、延音线
    Castle ActiveRecord学习实践(7):使用HQL查询
    C#中废弃一个方法小技巧
    加入BI团队,推荐一个商业智能的论坛
    .NET设计模式(13):享元模式(Flyweight Pattern)
    重载还是覆写?
    Castle ActiveRecord学习实践(2):构建配置信息
    使用WebClient上传文件时的错误问题解决
    Castle ActiveRecord学习实践(5):实现Many–Many关系的映射
    天津.NET俱乐部成立了!
  • 原文地址:https://www.cnblogs.com/kunsoft/p/13662288.html
Copyright © 2011-2022 走看看