Codeforces Round #668 (Div. 2)【ABCD】

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

A. Permutation Forgery

题意

给出一个大小为 $n$ 的排列 $p$,定义

egin{equation} F(p)=mathrm{sort}([p_1+p_2,p_2+p_3,ldots,p_{n-1}+p_n]) 。 onumber end{equation}

试找出一个不同于 $p$ 的 $p'$ 满足 $F(p') = F(p)$ 。

题解

反转 $p$ 即可。

代码

#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 (int i = 0; i < n; i++)
            cin >> a[i];
        reverse(a.begin(), a.end());
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << " 
"[i == a.size() - 1];
    }
    return 0;
}

B. Array Cancellation

题意

给出一个大小为 $n$,满足 $sum_{i=0}^{n-1} a_i = 0$ 的数组 $a$,每次可选择的操作如下:

  • 选择 $i < j$,将 $a_i$ 减一,$a_j$ 加一,花费为 $0$
  • 选择 $i > j$,将 $a_i$ 减一,$a_j$ 加一,花费为 $1$

问将 $a_i$ 均变为 $0$ 的最小花费是多少。

题解一

分别存储正数和负数的位置,然后贪心加双指针模拟。

代码

#include <bits/stdc++.h.>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> a(n);
        vector<int> posi, nega;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            if (a[i] > 0) posi.push_back(i);
            if (a[i] < 0) nega.push_back(i);
        }
        int j = 0;
        for (int i = 0; i < int(posi.size()); i++) {
            while (a[posi[i]] > 0) {
                while (j < int(nega.size()) and nega[j] < posi[i])
                    ++j;
                if (j == int(nega.size())) break;
                int mi = min(a[posi[i]], -a[nega[j]]);
                a[posi[i]] -= mi;
                a[nega[j]] += mi;
                if (a[nega[j]] == 0) ++j;
            }
        }    
        long long ans = 0;
        for (int i = 0; i < n; i++)
            if (a[i] > 0) ans += a[i];        
        cout << ans << "
";
    }
    return 0;
} 

题解二

最小负前缀的绝对值即为最少花费。

证明

对于最小负前缀,内部操作不会影响该负前缀的总和,涉及外部操作的最佳方案就是对负前缀加一,因为 $sum_{i=0}^{n-1} a_i = 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;
        long long ans = 0, cur = 0;
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            cur += x;
            ans = min(ans, cur);
        }
        cout << -ans << "
";
    }
    return 0;
}

C. Balanced Bitstring

题意

如果一个偶数长 $k$ 的二进制串有 $frac{k}{2}$ 个 $0$ 和 $1$,那么称这个二进制串为 $k$ 平衡串。给出一个由 $0,1,?$ 组成的字符串 $s$,$s$ 中的 $?$ 可被替换为 $0$ 或 $1$,判断 $s$ 是否可能为 $k$ 平衡串。

题解

因为共享中间的 $k-1$ 个字符,所以 $s_i = s_{i+k}$ 。

所以如果第一个 $k$ 长子串确定合法,则整个字符串确定合法。

另外还需枚举 $k$ 个起点并判断一开始的字符串中步长为 $k$ 的路径上的所有字符是否相同。

代码

#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, k;
        cin >> n >> k;
        string s;
        cin >> s;
        bool ok = true;
        int zero = 0, one = 0;
        for (int i = 0; i < k; i++) {
            bool a0 = false, a1 = false;
            for (int j = i; j < n; j += k)
                if (s[j] != '?')
                    (s[j] == '0' ? a0 : a1) = true;
            if (a0 and a1)
                ok = false;
            else if (a0 or a1)
                ++(a0 ? zero : one);
        }
        if (max(zero, one) > k / 2)
            ok = false;
        cout << (ok ? "YES" : "NO") << "
";
    }
    return 0;
}

D. Tree Tag

题意

给出一颗树,Alice在结点 $a$,每次可以走的距离最多为 $da$,Bob在结点 $b$,每次可以走的距离最多为 $db$,Alice先走,问在无限步内Alice能否走到Bob的位置。

题解

Alice获胜的三种情况:

  • 一开始Bob在Alice的覆盖半径内,因为Alice先手,所以一步就可以走到Bob的位置
  • Alice的覆盖直径大于等于树的直径,此时Alice可以移到树的中心并覆盖树上的每一个点
  • Alice的覆盖直径大于等于Bob的步长,此时以Alice的起点为根节点,Bob无法超出Alice的覆盖范围移到另一颗子树

代码

#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, a, b, da, db;
        cin >> n >> a >> b >> da >> db;
        --a, --b;
        vector<vector<int>> G(n);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            --u, --v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int diam = 0;
        vector<int> dep(n);
        function<int(int, int)> dfs = [&](int u, int p) {
            int len = 0;
            for (auto v : G[u]) {
                if (v != p) {
                    dep[v] = dep[u] + 1;
                    int cur = 1 + dfs(v, u);
                    diam = max(diam, cur + len);
                    len = max(len, cur);
                }
            }
            return len;
        };
        dfs(a, -1);
        cout << (2 * da >= min(diam, db) or dep[b] <= da ? "Alice" : "Bob") << "
";
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Kanoon/p/13657901.html