제출 #1330925

#제출 시각아이디문제언어결과실행 시간메모리
1330925beepbeepsheepIMO (EGOI25_imo)C++20
100 / 100
2654 ms566120 KiB
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

typedef tree<long long, null_type, less_equal<>,
        rb_tree_tag, tree_order_statistics_node_update>
        ordered_set;
        
#define ll long long
#define ii pair<ll,ll>
#define iii tuple<ll,ll,ll>

#ifndef DEBUG
#define cerr if (0) cerr
#define endl '\n'
#endif

const ll inf=1e15;
const ll maxn=2e4+5;
const ll mod=1e9+7;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

ll n, m, k;
vector<ii> v;
short scores[maxn][105];
bool dp[105][10005][105]; //index, excluded sum, number excluded
vector<tuple<short, short, int>> segments[maxn];

void reset(ll size) {
    for (int i = 1; i < 105; i++) {
        for (int j = 1; j <= size; j++) {
            for (int l = 1; l < 105; l++) {
                dp[i][j][l] = 0;
            }
        }
    }
}
void solve(ll size, ll idx, ll pos) {
    ll tot = v[pos].first;
    dp[0][0][0] = 1;
    for (int i = 1; i <= m; i++) {
        for (int j = 0; j <= size; j++) {
            for (int l = 0; l <= m; l++) {
                bool can1 = false, can2 = false;
                if (j - scores[idx][i] >= 0 && l - 1 >= 0){
                    can1 = dp[i - 1][j - scores[idx][i]][l - 1];
                }
                can2 = dp[i - 1][j][l];
                dp[i][j][l] = can1 | can2;
                if (dp[i][j][l]) {
                    segments[idx].emplace_back(tot - j + l * k, 
                        tot - j, l);
                }
            } 
        }
    }
}
int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        ll tot = 0;
        for (int j = 1; j <= m; j++) {
            cin >> scores[i][j];
            tot += scores[i][j];
        }
        v.emplace_back(tot, -i);
    }
    v.emplace_back(0, -inf);
    v.emplace_back(inf, -inf);
    sort(v.rbegin(), v.rend());
    for (int i = 0; i < v.size(); i++) {
        v[i].second = -v[i].second;
    }
    for (int i = 1; i <= n; i++) {
        ll diff = v[i].first - v[i + 1].first;
        ll idx = v[i].second;
        solve(diff, idx, i);
        reset(diff);
    }
    set<pair<short, int>> curr, prev;
    prev.emplace(m * k, 0);
    ll prevIdx = -1;
    for (auto [tot, idx]: v) {
        if (idx == inf) continue;
        sort(segments[idx].rbegin(), segments[idx].rend());
        bool tieBreak = idx < prevIdx;
        prevIdx = idx;
        for (auto [r, l, v]: segments[idx]) {
            auto it = prev.lower_bound(make_pair(r + tieBreak, -1));
            if  (it == prev.end()) continue;
            curr.emplace(l, it-> second + v);
        }
        auto it = --curr.end();
        --it;
        while (curr.size() > 1) {
            auto nxt = it;
            ++nxt;
            bool isErase = (it -> second <= nxt -> second);
            auto toErase = it;
            bool isBegin = (it == curr.begin());
            --it;
            if (isErase) {
                curr.erase(toErase);
            }
            if (isBegin) break;
        }
        swap(curr, prev);
        curr.clear();
    }
    cout << m * n - prev.begin() -> second;
    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...