제출 #1333969

#제출 시각아이디문제언어결과실행 시간메모리
1333969rahulsharma1023IMO (EGOI25_imo)C++20
100 / 100
107 ms10408 KiB
#include <bits/stdc++.h>
using namespace std;

static const int NEG = -1e9;
static const int MAXM = 100;

vector<signed char> build_pref(const vector<int>& scores, int right_cap, int m) {
    vector<bitset<MAXM + 1>> masks(right_cap + 1);
    masks[0][0] = 1; // sum 0 with 0 hidden scores

    for (int a : scores) {
        for (int sum = right_cap; sum >= a; --sum) {
            masks[sum] |= (masks[sum - a] << 1);
        }
    }

    vector<signed char> pref((right_cap + 1) * (m + 1), -1);
    for (int sum = 0; sum <= right_cap; ++sum) {
        int best = -1;
        for (int h = 0; h <= m; ++h) {
            if (masks[sum][h]) best = h;
            pref[sum * (m + 1) + h] = (signed char)best;
        }
    }
    return pref;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M, K;
    cin >> N >> M >> K;

    vector<vector<int>> scores(N, vector<int>(M));
    vector<int> total(N, 0);
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            cin >> scores[i][j];
            total[i] += scores[i][j];
        }
    }

    vector<int> order(N);
    iota(order.begin(), order.end(), 0);
    sort(order.begin(), order.end(), [&](int x, int y) {
        if (total[x] != total[y]) return total[x] > total[y];
        return x < y;
    });

    vector<int> g(N - 1);
    for (int i = 0; i + 1 < N; ++i) {
        int x = order[i], y = order[i + 1];
        g[i] = total[x] - total[y] - (x > y ? 1 : 0);
    }

    // First contestant: only the uncertainty towards the right matters.
    vector<signed char> first_pref = build_pref(scores[order[0]], g[0], M);
    vector<int> dp(g[0] + 1, NEG);
    for (int a = 0; a <= g[0]; ++a) {
        dp[a] = first_pref[a * (M + 1) + M];
    }

    // Middle contestants.
    for (int pos = 1; pos + 1 < N; ++pos) {
        int left_cap = g[pos - 1];
        int right_cap = g[pos];
        vector<signed char> pref = build_pref(scores[order[pos]], right_cap, M);
        vector<int> next_dp(right_cap + 1, NEG);

        for (int prev_a = 0; prev_a <= left_cap; ++prev_a) {
            if (dp[prev_a] <= NEG / 2) continue;
            int left_budget = left_cap - prev_a;
            int base = dp[prev_a];
            for (int cur_a = 0; cur_a <= right_cap; ++cur_a) {
                int limit = (cur_a + left_budget) / K;
                if (limit > M) limit = M;
                int h = pref[cur_a * (M + 1) + limit];
                if (h >= 0) {
                    next_dp[cur_a] = max(next_dp[cur_a], base + h);
                }
            }
        }
        dp.swap(next_dp);
    }

    // Last contestant: only the uncertainty towards the left matters.
    int last_cap = g.back();
    vector<int> deficits;
    deficits.reserve(M);
    for (int a : scores[order.back()]) deficits.push_back(K - a);
    sort(deficits.begin(), deficits.end());

    vector<int> pref_def(M + 1, 0);
    for (int i = 0; i < M; ++i) pref_def[i + 1] = pref_def[i] + deficits[i];

    vector<int> best_last(last_cap + 1, 0);
    int h = 0;
    for (int budget = 0; budget <= last_cap; ++budget) {
        while (h + 1 <= M && pref_def[h + 1] <= budget) ++h;
        best_last[budget] = h;
    }

    int max_hidden = 0;
    for (int prev_a = 0; prev_a <= last_cap; ++prev_a) {
        if (dp[prev_a] <= NEG / 2) continue;
        max_hidden = max(max_hidden, dp[prev_a] + best_last[last_cap - prev_a]);
    }

    cout << N * M - max_hidden << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...