Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final)【ABCDF】
阅读原文时间:2023年07月10日阅读:5

比赛链接:https://codeforces.com/contest/1443

A. Kids Seating

构造一个大小为 \(n\) 的数组使得任意两个数既不互质也不相互整除,要求所有数小于 \(4n\) 。

因为不互质所以 \(gcd\) 至少为 \(2\),又为了避免相互整除,可以从倒着较大的 \(4n\) 开始构造。

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> v;
        for (int i = 4 * n; int(v.size()) < n; i -= 2) {
            v.push_back(i);
        }
        for (int i = 0; i < n; i++) {
            cout << v[i] << " \n"[i == n - 1];
        }
    }
    return 0;
}

B. Saving the City

给出一个 \(01\) 串,有两种操作:

  • 消除一段连续的 \(1\),花费为 \(a\)
  • 将一个 \(0\) 变为 \(1\),花费为 \(b\)

问将字符串全变为 \(0\) 的最小花费是多少。

记录所有连续 \(1\) 区间的左右端点,然后尝试合并相邻区间。

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int a, b;
        cin >> a >> b;
        string s;
        cin >> s;
        int n = s.size();
        vector<pair<int, int>> v;
        for (int i = 0; i < n; ) {
            int j = i + 1;
            if (s[i] == '1') {
                while (j < n and s[j] == '1') ++j;
                v.emplace_back(i, j);
            }
            i = j;
        }
        int ans = v.size() * a;
        for (int i = 1; i < int(v.size()); i++) {
            auto [l1, r1] = v[i - 1];
            auto [l2, r2] = v[i];
            if ((l2 - r1) * b <= a) {
                ans -= a - (l2 - r1) * b;
            }
        }
        cout << ans << "\n";
    }
    return 0;
}

C. The Delivery Dilemma

给出 \(n\) 份食物外送和自取需要的时间,外送是同时开始的,自取需要依次进行,问最少要花费多少时间才能取到所有食物。

将食物按照外送时间从小到大排序,计算自取时间的后缀和,从前向后枚举外送食物的最大时间,取与后缀和之和的最小值即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<pair<int, int>> v(n);
        for (auto &[x, y] : v) cin >> x;
        for (auto &[x, y] : v) cin >> y;
        sort(v.begin(), v.end());
        vector<long long> suf(n + 1);
        for (int i = n - 1; i >= 0; i--) {
            suf[i] = suf[i + 1] + v[i].second;
        }
        long long ans = 0;
        for (auto [x, y] : v) ans += y;
        for (int i = 0; i < n; i++) {
            ans = min(ans, max(v[i].first * 1LL, suf[i + 1]));
        }
        cout << ans << "\n";
    }
    return 0;
}

D. Extreme Subtraction

给出一个大小为 \(n\) 的数组 \(a\),每次操作有两种选择:

  • 取最左端的一段连续区间,将区间内的数全部减一
  • 取最右端的一段连续区间,将区间内的数全部减一

判断能否使所有数都变为 \(0\) 。

如果一个数大于它右边的数,那么它及左端的数一定要连续减差值次,判断是否有数最终减的次数大于原值即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> a(n);
        for (auto &x : a) cin >> x;
        for (int i = n - 2; i >= 0; i--) {
            if (a[i] > a[i + 1]) {
                for (int j = 0; j <= i; j++) a[j] -= a[i] - a[i + 1];
            }
        }
        cout << (any_of(a.begin(), a.end(), [](int x) { return x < 0; }) ? "NO" : "YES") << "\n";
    }
    return 0;
}

F. Identify the Operations

给出一个大小为 \(n\) 的排列,每次操作可以删除 \(a_{i-1}\) 或 \(a_{i+1}\) 来选取 \(a_i\),给出最终选取的序列,计算可以得到该序列的方案数。

存储每个值的位置,并在一开始删除所有在最终序列中的数的位置,每次选取后再将该位置存入。

#include <bits/stdc++.h>
using namespace std;
constexpr int MOD = 998244353;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        vector<int> pos(n);
        set<int> st;
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            --x;
            pos[x] = i;
            st.insert(pos[x]);
        }
        vector<int> b(k);
        for (auto &x : b) {
            cin >> x;
            --x;
            st.erase(pos[x]);
        }
        long long ans = 1;
        for (auto x : b) {
            ans = ans * (st.count(pos[x] - 1) + st.count(pos[x] + 1)) % MOD;
            st.insert(pos[x]);
        }
        cout << ans << "\n";
    }
    return 0;
}