Codeforces Round 998 (Div.3) 解説: A-D問題の解法と実装例

コンテスト参加後の復習と解法の整理を行います。問題AからDまでのアプローチとコードをまとめました。

A. Fibonacciness

5要素の数列における最大の「フィボナッチ度」を求める問題です。数列の長さが5であるため、最大でも度は3となります。各位置で成立するフィボナッチ関係の式を検討します。

具体的には、a0+a1 = a2、a1+a2 = a3、a2+a3 = a4の3つの条件が考えられます。これらを満たすよう、未知の要素を決定するパターンをsetで管理し、残りの自由度を求めます。

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    
    while (t--) {
        vector<int> a(4);
        for (int i = 0; i < 4; ++i) cin >> a[i];
        
        unordered_set<int> candidates;
        candidates.insert(a[0] + a[1]);
        candidates.insert(a[2] - a[1]);
        candidates.insert(a[3] - a[2]);
        
        cout << 4 - candidates.size() << '\n';
    }
    
    return 0;
}

B. Farmer John's Card Game

各プレイヤーのカードセットが与えられ、全プレイヤーが順番にカードを出し合うゲームにおいて、カードの値が昇順になるような初期配置を求める問題です。

解法では、各プレイヤーのカードをソートした後、最小カードでプレイヤーを並べ替えます。その後、全てのカードを順に確認して昇順条件が満たされているかを検証します。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

void solve() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<ll>> cards(n, vector<ll>(m));
    vector<pair<ll, int>> minCard;
    
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> cards[i][j];
        }
        sort(cards[i].begin(), cards[i].end());
        minCard.emplace_back(cards[i][0], i);
    }
    
    sort(minCard.begin(), minCard.end());
    
    vector<int> order;
    for (auto& p : minCard) order.push_back(p.second);
    
    ll last = -1;
    bool valid = true;
    
    for (int col = 0; col < m && valid; ++col) {
        for (int row = 0; row < n && valid; ++row) {
            int player = order[row];
            if (cards[player][col] <= last) {
                valid = false;
            } else {
                last = cards[player][col];
            }
        }
    }
    
    if (!valid) {
        cout << -1 << '\n';
    } else {
        for (int i = 0; i < n; ++i) {
            cout << order[i] + 1 << " \n"[i == n - 1];
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) solve();
    
    return 0;
}

C. Game of Mathletes

数列から2つの数をペアにし、その和が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;
        
        vector<int> a(n);
        unordered_map<int, int> freq;
        
        for (int i = 0; i < n; ++i) {
            cin >> a[i];
            freq[a[i]]++;
        }
        
        int pairs = 0;
        for (int i = 1; i <= k / 2; ++i) {
            if (k % 2 == 0 && i == k / 2) {
                pairs += freq[i] / 2;
            } else {
                pairs += min(freq[i], freq[k - i]);
            }
        }
        
        cout << pairs << '\n';
    }
    
    return 0;
}

D. Subtract Min Sort

隣接する2要素から最小値を同時に引く操作を繰り返し、最終的に非減少列にできるかを判定する問題です。左から順に操作を適用し、条件を満たさなくなるケースを検出します。

#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];
        
        bool possible = true;
        
        for (int i = 1; i < n; ++i) {
            if (a[i - 1] > a[i]) {
                possible = false;
                break;
            }
            int sub = min(a[i - 1], a[i]);
            a[i - 1] -= sub;
            a[i] -= sub;
        }
        
        cout << (possible ? "YES" : "NO") << '\n';
    }
    
    return 0;
}

タグ: codeforces 競技プログラミング フィボナッチ数列 ソートアルゴリズム ハッシュマップ

6月22日 17:44 投稿