1. 程式人生 > 實用技巧 >Educational Codeforces Round 97 (Rated for Div. 2)【ABCD】

Educational Codeforces Round 97 (Rated for Div. 2)【ABCD】

比賽連結:https://codeforces.com/contest/1437

A. Marketing Scheme

題解

\(l = \frac{a}{2}\),那麼如果 \(r < a\),每個顧客都會買更多貓糧。

程式碼

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int l, r;
        cin >> l >> r;
        cout << (r < 2 * l ? "YES" : "NO") << "\n";
    }
    return 0;
}

B. Reverse Binary Strings

題解

如果有一個連續 \(0\)\(1\) 區間長度大於 \(1\),那麼多出來的這部分中的每個數都是需要翻轉的。答案即連續 \(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 n;
        cin >> n;
        string s;
        cin >> s;
        int ans[2] = {};
        for (int i = 0; i < n; ) {
            int j = i + 1;
            while (j < n and s[j] == s[i]) ++j;
            ans[s[i] - '0'] += j - i - 1;
            i = j;
        }
        cout << max(ans[0], ans[1]) << "\n";
    }
    return 0;
}

C. Chef Monocarp

題解一

\(dp_{ij}\) 的含義為 \(i\) 個點放前 \(j\) 個數的最小花費。

程式碼

#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> t(n);
        for (auto &x : t) cin >> x;
        sort(t.begin(), t.end());
        vector<vector<int>> dp(2 * n + 1, vector<int>(2 * n + 1, 1e9));
        for (int i = 0; i < 2 * n + 1; i++)
            dp[i][0] = 0;
        for (int i = 1; i <= 2 * n; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1] + abs(t[j - 1] - i));
            }
        }
        cout << dp[2 * n][n] << "\n";
    }
    return 0;
}

題解二

由於每層的狀態取決於上一層,所以可以倒序遍歷,空間複雜度因此由 \(S_{(n^2)}\) 優化至 \(S_{(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<int> t(n);
        for (auto &x : t) cin >> x;
        sort(t.begin(), t.end());
        vector<int> dp(n + 1, 1e9);
        dp[0] = 0;
        for (int i = 1; i <= 2 * n; i++) {
            for (int j = n; j >= 1; j--) {
                dp[j] = min(dp[j], dp[j - 1] + abs(t[j - 1] - i));
            }
        }
        cout << dp[n] << "\n";
    }
    return 0;
}

D. Minimal Height Tree

題解

\(bfs\) 序列分割為一個個連續遞增區間,每個遞增區間都可以歸到上一層的一個結點上。

程式碼

#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;
        vector<int> seg;
        for (int i = 1; i < n; ) {
            int j = i + 1;
            while (j < n and a[j] > a[j - 1]) ++j;
            seg.push_back(j - i);
            i = j;
        }
        int height = 0;
        int prv = 1, nxt = 0;
        for (int i = 0; i < int(seg.size()); ) {
            ++height;
            nxt = accumulate(seg.begin() + i, min(seg.end(), seg.begin() + i + prv), 0);
            i += prv;
            prv = nxt;
        }
        cout << height << "\n";
    }
    return 0;
}