配列と集合の問題解説: Codeforces Round 932 (Div. 2)

C. メッセンジャープログラム

2つの配列aとb、および整数Lが与えられます。aとbのインデックスのシーケンスpを見つけて、\(\sum a_{p_i} + \sum |b_{p_i}-b_{p_{i+1}}| \leq L\)を満たす必要があります。

解法

キー1:bを昇順にソートすることが最適です。

キー2:固定された\(b_l\)と\(b_r\)に対して、\(\sum^r_l |b_{p_i}-b_{p_{i+1}}| = b_r - b_l\)となり、これは固定値なので、中間のa_iとb_iを任意に削除できます。必要なのは\(\sum a \leq L - (b_r - b_l)\)だけです。

lを固定し、左から右へ拡張します。優先度キューを使って現在のaの最大値を維持し、合計が超えた場合は最大要素を削除します。

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

typedef long long ll;

void solve() {
    int n, L;
    cin >> n >> L;
    vector<pair<int, int>> arr(n);
    for (int i = 0; i < n; ++i)
        cin >> arr[i].second >> arr[i].first; // first: b, second: a

    sort(arr.begin(), arr.end());
    int result = 0;
    for (int left = 0; left < n; ++left) {
        priority_queue<int> pq;
        int total = 0;
        for (int right = left; right < n; ++right) {
            pq.push(arr[right].second);
            total += arr[right].second;
            while (!pq.empty() && total > L - (arr[right].first - arr[left].first)) {
                total -= pq.top();
                pq.pop();
            }
            result = max(result, static_cast<int>(pq.size()));
        }
    }

    cout << result << '\n';
}

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

時間計算量:O(n^2 log n)

D. 試験問題

集合sと正整数cが与えられ、0からcまでの範囲で(x, y)ペアの個数を求めます。条件はx + y ∉ sかつy - x ∉ sです。

解法

直接的に条件を満たすx, yを計算するのは困難です。しかし、すべての場合から不適切なケースを引くことで解決できます。

すべての場合の数は\(C^{2}_{n+2}\)(具体的な組み合わせを考えてみてください)です。

仮定として、x + y = t ∈ sの場合、その場合の数は(t / 2 + 1)となります。同様に、y - x = t ∈ sの場合、その場合の数は(c - t + 1)となります。ただし、これらの二つの状況には重複があります。例えば、1 + 2 = 3と2 - 1 = 1のように、両方の条件で同じペアが考慮されることがあります。

この重複を避けるため、奇数と偶数のグループに分割します。重複するケースは必ず一方のグループから選ばれます。

最終的な答えは以下のようになります: [ ans = C^{2}{n+2} - \sum{\forall t \in S} (t/2 + 1) - \sum_{\forall t \in S} (c - t + 1) + C^{2}* + C^{2}* + n ]

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

typedef long long ll;

void solve() {
    int n, c;
    cin >> n >> c;
    int odd = 0, even = 0;
    vector<int> nums(n);
    for (int i = 0; i < n; ++i) {
        cin >> nums[i];
        if (nums[i] % 2) odd++;
        else even++;
    }

    int result = (c + 1) * (c + 2) / 2;
    for (int i = 0; i < n; ++i) {
        result -= nums[i] / 2 + 1;
        result -= (c - nums[i] + 1);
    }
    result += (odd * (odd - 1)) / 2 + (even * (even - 1)) / 2;
    result += n;
    cout << result << '\n';
}

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

タグ: codeforces 競技プログラミング C++ アルゴリズム データ構造

9月28日 13:57 投稿