Submission #612386

#TimeUsernameProblemLanguageResultExecution timeMemory
612386erekleCarnival Tickets (IOI20_tickets)C++17
41 / 100
733 ms59868 KiB
#include "tickets.h" #include <vector> #include <algorithm> #include <cassert> using namespace std; const long long INF = 1e18; long long find_maximum(int k, vector<vector<int>> x) { int n = x.size(); int m = x[0].size(); vector<vector<int>> answer(n, vector<int>(m, -1)); long long prize = 0; int MAX = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { MAX = max(MAX, x[i][j]); } } if (k == 1) { vector<vector<long long>> dp(1+n, vector<long long>(1+n/2, -INF)); dp[0][0] = 0; // dp on prefix and number of positives vector<vector<bool>> chosePositive(1+n, vector<bool>(1+n/2)); // chosePositive allows backtracking for (int i = 0; i < n; ++i) { for (int pos = 0; 2*pos <= n; ++pos) { if (dp[i][pos] == -INF) continue; // do not choose positive long long v = dp[i][pos] - x[i].front(); if (v > dp[i+1][pos]) { dp[i+1][pos] = v; chosePositive[i+1][pos] = false; } // choose positive (if possible) if (2*pos == n) continue; // no more positives v = dp[i][pos] + x[i].back(); if (v > dp[i+1][pos+1]) { dp[i+1][pos+1] = v; chosePositive[i+1][pos+1] = true; } } } prize = dp[n][n>>1]; // Now reconstruct answer for (int i = n, pos = n>>1; i >= 1; --i) { if (!chosePositive[i][pos]) answer[i-1][0] = 0; else answer[i-1][m-1] = 0, pos--; } } else if (m == k) { vector<int> cnt[2], remain[2]; cnt[0].resize(n), cnt[1].resize(n); remain[0].resize(n), remain[1].resize(n); vector<pair<int, int>> v; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) v.emplace_back(x[i][j], i); } sort(v.begin(), v.end()); for (int i = 0; (i<<1) < n*m; ++i) { ++cnt[0][v[i].second]; } for (int i = 0; i < n; ++i) { cnt[1][i] = m-cnt[0][i]; remain[0][i] = cnt[0][i]; remain[1][i] = cnt[1][i]; } for (int i = 0; i < k; ++i) { int used0 = 0; for (int y = 0; y < n; ++y) { if (!remain[1][y]) { // zero prize -= x[y][cnt[0][y]-remain[0][y]]; answer[y][cnt[0][y]-remain[0][y]] = i; --remain[0][y]; ++used0; } else if (!remain[0][y]) { // one prize += x[y][cnt[0][y]+remain[1][y]-1]; answer[y][cnt[0][y]+remain[1][y]-1] = i; --remain[1][y]; } } for (int y = 0; y < n; ++y) { // both if (!remain[0][y] || !remain[1][y]) continue; if (2*used0 < n) { prize -= x[y][cnt[0][y]-remain[0][y]]; answer[y][cnt[0][y]-remain[0][y]] = i; --remain[0][y]; ++used0; } else { prize += x[y][cnt[0][y]+remain[1][y]-1]; answer[y][cnt[0][y]+remain[1][y]-1] = i; --remain[1][y]; } } } } else if (MAX == 1) { int z = 0, o = 0; vector<int> got0(n), got1(n); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (x[i][j] == 0) ++z, ++got0[i]; else ++o, ++got1[i]; } } // have to remove (m-k)*n int zTarget = 0, rem = (m-k)*n; zTarget = (rem+(z-o))/2; int mnRemove = 0, mxRemove = 0; // zeros removed vector<int> mn(1+n), mx(1+n); for (int i = 0; i < n; ++i) { mnRemove += max(m-k-got1[i], 0); mxRemove += min(m-k, got0[i]); mn[i+1] = mnRemove; mx[i+1] = mxRemove; } // Recalculate realistic target if (zTarget < mnRemove) zTarget = mnRemove; if (zTarget > mxRemove) zTarget = mxRemove; // Remove so that target is achieved vector<int> removed0(n), removed1(n); for (int i = n; i >= 1; --i) { int least = max(m-k-got1[i-1], 0); int most = min(m-k, got0[i-1]); int largestAfter = mx[i-1]; removed0[i-1] = max(zTarget-largestAfter, least); assert(least <= removed0[i-1] && removed0[i-1] <= most); removed1[i-1] = m-k-removed0[i-1]; zTarget -= removed0[i-1]; } // This is the same as the solution to m=k except one detail below vector<int> cnt[2], remain[2]; cnt[0].resize(n), cnt[1].resize(n); remain[0].resize(n), remain[1].resize(n); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (x[i][j] == 0) ++cnt[0][i]; } } // vector<pair<int, int>> v; // for (int i = 0; i < n; ++i) { // for (int j = 0; j < m; ++j) v.emplace_back(x[i][j], i); // } // sort(v.begin(), v.end()); // for (int i = 0; (i<<1) < n*m; ++i) { // ++cnt[0][v[i].second]; // } for (int i = 0; i < n; ++i) { cnt[1][i] = m-cnt[0][i]; remain[0][i] = cnt[0][i]; remain[1][i] = cnt[1][i]; // Here we are subtracting removed from remain remain[0][i] -= removed0[i]; remain[1][i] -= removed1[i]; assert(remain[0][i] >= 0 && remain[0][i] <= cnt[0][i]); assert(remain[1][i] >= 0 && remain[1][i] <= cnt[1][i]); } for (int i = 0; i < k; ++i) { int used0 = 0; for (int y = 0; y < n; ++y) { if (!remain[1][y]) { // zero assert(remain[0][y]); prize -= x[y][cnt[0][y]-remain[0][y]]; answer[y][cnt[0][y]-remain[0][y]] = i; --remain[0][y]; ++used0; } else if (!remain[0][y]) { // one assert(remain[1][y]); prize += x[y][cnt[0][y]+remain[1][y]-1]; answer[y][cnt[0][y]+remain[1][y]-1] = i; --remain[1][y]; } } for (int y = 0; y < n; ++y) { // both if (!remain[0][y] || !remain[1][y]) continue; if (2*used0 < n) { prize -= x[y][cnt[0][y]-remain[0][y]]; answer[y][cnt[0][y]-remain[0][y]] = i; --remain[0][y]; ++used0; } else { prize += x[y][cnt[0][y]+remain[1][y]-1]; answer[y][cnt[0][y]+remain[1][y]-1] = i; --remain[1][y]; } } } } allocate_tickets(answer); return prize; }
#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...