Submission #421163

#TimeUsernameProblemLanguageResultExecution timeMemory
421163rama_pangIzvanzemaljci (COI21_izvanzemaljci)C++17
100 / 100
1584 ms25448 KiB
#include <bits/stdc++.h> using namespace std; using lint = long long; int main() { ios::sync_with_stdio(0); cin.tie(0); int N, K; cin >> N >> K; vector<lint> X(N), Y(N); for (int i = 0; i < N; i++) { cin >> X[i] >> Y[i]; } long long answerScore = 1e18; vector<array<lint, 4>> answer; for (int rot = 0; rot < 4; rot++) { vector<int> sortByX(N); vector<int> sortByY(N); iota(begin(sortByX), end(sortByX), 0); iota(begin(sortByY), end(sortByY), 0); sort(begin(sortByX), end(sortByX), [&](int i, int j) { return pair(X[i], Y[i]) < pair(X[j], Y[j]); }); sort(begin(sortByY), end(sortByY), [&](int i, int j) { return pair(Y[i], X[i]) < pair(Y[j], X[j]); }); vector<int> posInSortByX(N); vector<int> posInSortByY(N); for (int i = 0; i < N; i++) { posInSortByX[sortByX[i]] = i; posInSortByY[sortByY[i]] = i; } const auto CountingSort = [&](vector<int> &a, const vector<int> &sorted, const vector<int> &pos) { static vector<int> res(N); fill(begin(res), end(res), 0); for (auto i : a) { res[pos[i]] = 1; } a.clear(); for (int i = 0; i < N; i++) { if (res[i]) { a.emplace_back(sorted[i]); } } }; vector<array<lint, 3>> ans; const auto SolveK1 = [&](vector<int> alive, lint boundLftX, lint boundRgtX, lint boundLftY, lint boundRgtY, int trace) -> lint { if (alive.empty()) return 0; lint minX = +2e9; lint maxX = -2e9; lint minY = +2e9; lint maxY = -2e9; for (auto i : alive) { minX = min(minX, X[i]); maxX = max(maxX, X[i]); minY = min(minY, Y[i]); maxY = max(maxY, Y[i]); } lint len = max({1ll, maxX - minX, maxY - minY}); if (boundRgtX - boundLftX < len) return 1e18; if (boundRgtY - boundLftY < len) return 1e18; if (!trace) { return len; } for (auto x : {boundLftX, minX, maxX - len, boundRgtX - len}) if (-3e9 <= x && x <= 3e9) { if (boundLftX <= x && x + len <= boundRgtX) { for (auto y : {boundLftY, minY, maxY - len, boundRgtY - len}) if (-3e9 <= y && y <= 3e9) { if (boundLftY <= y && y + len <= boundRgtY) { bool bad = false; for (auto i : alive) { if (x <= X[i] && X[i] <= x + len && y <= Y[i] && Y[i] <= y + len) { } else { bad = true; break; } } if (!bad) { ans.push_back({x, y, len}); return len; } } } } } assert(false); return 1e18; }; map<tuple<vector<int>, int, lint>, lint> memoK2; const auto SolveK2 = [&](vector<int> alive, int vert, lint boundLftX, int trace) -> lint { if (alive.empty()) return 0; if (auto it = memoK2.find({alive, vert, boundLftX}); trace == 0 && it != end(memoK2)) { return it->second; } lint res = SolveK1(alive, boundLftX, 1e18, -1e18, 1e18, 0); if (!vert) { CountingSort(alive, sortByY, posInSortByY); } else { CountingSort(alive, sortByX, posInSortByX); } static vector<lint> prefMinX(N); static vector<lint> prefMaxX(N); static vector<lint> prefMinY(N); static vector<lint> prefMaxY(N); static vector<lint> suffMinX(N); static vector<lint> suffMaxX(N); static vector<lint> suffMinY(N); static vector<lint> suffMaxY(N); for (int i = 0; i < int(alive.size()); i++) { int id = alive[i]; prefMinX[i] = prefMaxX[i] = X[id]; prefMinY[i] = prefMaxY[i] = Y[id]; suffMinX[i] = suffMaxX[i] = X[id]; suffMinY[i] = suffMaxY[i] = Y[id]; } for (int i = 1; i < int(alive.size()); i++) { prefMinX[i] = min(prefMinX[i], prefMinX[i - 1]); prefMaxX[i] = max(prefMaxX[i], prefMaxX[i - 1]); prefMinY[i] = min(prefMinY[i], prefMinY[i - 1]); prefMaxY[i] = max(prefMaxY[i], prefMaxY[i - 1]); } for (int i = int(alive.size()) - 2; i >= 0; i--) { suffMinX[i] = min(suffMinX[i], suffMinX[i + 1]); suffMaxX[i] = max(suffMaxX[i], suffMaxX[i + 1]); suffMinY[i] = min(suffMinY[i], suffMinY[i + 1]); suffMaxY[i] = max(suffMaxY[i], suffMaxY[i + 1]); } const auto CalcPref = [&](int i) -> lint { if (i < 0 || i >= int(alive.size())) return 0; return max(prefMaxX[i] - prefMinX[i], prefMaxY[i] - prefMinY[i]); }; const auto CalcSuff = [&](int i) -> lint { if (i < 0 || i >= int(alive.size())) return 0; return max(suffMaxX[i] - suffMinX[i], suffMaxY[i] - suffMinY[i]); }; if (vert == 0) { for (int i = 0; i < int(alive.size()); i++) { if (!(i + 1 == int(alive.size()) || Y[alive[i + 1]] != Y[alive[i]])) { continue; } res = min(res, max(CalcPref(i), CalcSuff(i + 1))); } if (res == 1e18) { return memoK2[{alive, vert, boundLftX}] = res; } vector<int> pref; vector<int> suff = alive; reverse(begin(suff), end(suff)); for (int i = 0; i < int(alive.size()); i++) { pref.emplace_back(alive[i]); suff.pop_back(); if (!(i + 1 == int(alive.size()) || Y[alive[i + 1]] != Y[alive[i]])) { continue; } if (res == max(CalcPref(i), CalcSuff(i + 1))) { SolveK1(pref, boundLftX, 1e18, -1e18, Y[alive[i]], trace); SolveK1(suff, boundLftX, 1e18, Y[alive[i]] + 1, 1e18, trace); return memoK2[{alive, vert, boundLftX}] = res; } } } else { for (int i = 0; i < int(alive.size()); i++) { if (!(i + 1 == int(alive.size()) || X[alive[i + 1]] != X[alive[i]])) { continue; } lint len = CalcPref(i); lint upTo = (i + 1 == int(alive.size())) ? 1e18 : (X[alive[i + 1]] - 1); if (upTo - max(boundLftX, prefMinX[i]) < len) continue; res = min(res, max(CalcPref(i), CalcSuff(i + 1))); } if (res == 1e18) { return memoK2[{alive, vert, boundLftX}] = res; } vector<int> pref; vector<int> suff = alive; reverse(begin(suff), end(suff)); for (int i = 0; i < int(alive.size()); i++) { pref.emplace_back(alive[i]); suff.pop_back(); if (!(i + 1 == int(alive.size()) || X[alive[i + 1]] != X[alive[i]])) { continue; } lint len = CalcPref(i); lint upTo = (i + 1 == int(alive.size())) ? 1e18 : (X[alive[i + 1]] - 1); if (upTo - max(boundLftX, prefMinX[i]) < len) continue; if (res == max(CalcPref(i), CalcSuff(i + 1))) { SolveK1(pref, boundLftX, upTo, -1e18, 1e18, trace); SolveK1(suff, upTo + 1, 1e18, -1e18, 1e18, trace); return memoK2[{alive, vert, boundLftX}] = res; } } } if (res == SolveK1(alive, boundLftX, 1e18, -1e18, 1e18, 0)) { return memoK2[{alive, vert, boundLftX}] = SolveK1(alive, boundLftX, 1e18, -1e18, 1e18, trace); } return memoK2[{alive, vert, boundLftX}] = 1e18; }; const auto SolveK3 = [&](vector<int> alive, int trace) -> lint { lint res = 1e18; res = min(res, SolveK2(alive, 0, -1e18, 0)); res = min(res, SolveK2(alive, 1, +1e18, 0)); CountingSort(alive, sortByX, posInSortByX); static vector<lint> prefMinX(N); static vector<lint> prefMaxX(N); static vector<lint> prefMinY(N); static vector<lint> prefMaxY(N); for (int i = 0; i < int(alive.size()); i++) { int id = alive[i]; prefMinX[i] = prefMaxX[i] = X[id]; prefMinY[i] = prefMaxY[i] = Y[id]; } for (int i = 1; i < int(alive.size()); i++) { prefMinX[i] = min(prefMinX[i], prefMinX[i - 1]); prefMaxX[i] = max(prefMaxX[i], prefMaxX[i - 1]); prefMinY[i] = min(prefMinY[i], prefMinY[i - 1]); prefMaxY[i] = max(prefMaxY[i], prefMaxY[i - 1]); } const auto CalcPref = [&](int i) -> lint { if (i < 0 || i >= int(alive.size())) return 0; return max(prefMaxX[i] - prefMinX[i], prefMaxY[i] - prefMinY[i]); }; vector<lint> coordX = X; sort(begin(coordX), end(coordX)); coordX.resize(unique(begin(coordX), end(coordX)) - begin(coordX)); const auto Check = [&](lint maxD) -> pair<int, bool> { int ok = -1; for (int i = 0; i < int(alive.size()); i++) { if (!(i + 1 == int(alive.size()) || X[alive[i + 1]] != X[alive[i]])) { continue; } if (CalcPref(i) <= maxD) { ok = i; } } vector<int> other; for (int i = ok + 1; i < int(alive.size()); i++) { other.emplace_back(alive[i]); } return {ok, min(SolveK2(other, 0, ok == -1 ? -1e18 : (X[alive[ok]] + 1), 0), SolveK2(other, 1, ok == -1 ? -1e18 : (X[alive[ok]] + 1), 0)) <= maxD}; }; lint lo = 1, hi = 2e9; while (lo < hi) { lint md = (lo + hi) / 2; if (Check(md).second) { hi = md; } else { lo = md + 1; } } int cand = Check(lo).first; vector<int> suff = alive; reverse(begin(suff), end(suff)); for (int i = 0; i < int(alive.size()); i++) { suff.pop_back(); if (!(i + 1 == int(alive.size()) || X[alive[i + 1]] != X[alive[i]])) { continue; } if (i != cand) continue; res = min(res, max(CalcPref(i), SolveK2(suff, 0, X[alive[i]] + 1, 0))); res = min(res, max(CalcPref(i), SolveK2(suff, 1, X[alive[i]] + 1, 0))); } if (res == 1e18) { return res; } suff = alive; vector<int> pref; reverse(begin(suff), end(suff)); for (int i = 0; i < int(alive.size()); i++) { pref.emplace_back(alive[i]); suff.pop_back(); if (!(i + 1 == int(alive.size()) || X[alive[i + 1]] != X[alive[i]])) { continue; } if (i != cand) continue; if (res == max(CalcPref(i), SolveK2(suff, 0, X[alive[i]] + 1, 0))) { SolveK1(pref, -1e18, X[alive[i]], -1e18, 1e18, trace); SolveK2(suff, 0, X[alive[i]] + 1, trace); return res; } if (res == max(CalcPref(i), SolveK2(suff, 1, X[alive[i]] + 1, 0))) { SolveK1(pref, -1e18, X[alive[i]], -1e18, 1e18, trace); SolveK2(suff, 1, X[alive[i]] + 1, trace); return res; } } if (res == SolveK2(alive, 0, -1e18, 0)) { return SolveK2(alive, 0, -1e18, trace); } if (res == SolveK2(alive, 1, -1e18, 0)) { return SolveK2(alive, 1, -1e18, trace); } return 1e18; }; const auto Solve = [&](int K, int trace) -> lint { vector<int> alive(N); iota(begin(alive), end(alive), 0); if (K == 1) { ans.clear(); return SolveK1(alive, -1e18, 1e18, -1e18, 1e18, trace); } else if (K == 2) { ans.clear(); lint res1 = SolveK2(alive, 0, -1e18, trace); auto ans1 = ans; ans.clear(); lint res2 = SolveK2(alive, 1, -1e18, trace); auto ans2 = ans; if (res1 < res2) { ans = ans1; return res1; } else { ans = ans2; return res2; } } else if (K == 3) { ans.clear(); return SolveK3(alive, trace); } else { assert(false); return -1; } }; lint res = Solve(K, 1); if (res < answerScore) { answerScore = res; answer.clear(); for (auto &a : ans) { answer.push_back({a[0], a[1], a[0] + a[2], a[1] + a[2]}); } } for (int i = 0; i < N; i++) { swap(X[i], Y[i]); Y[i] *= -1; } for (int i = 0; i < int(answer.size()); i++) { swap(answer[i][0], answer[i][1]); answer[i][1] *= -1; swap(answer[i][2], answer[i][3]); answer[i][3] *= -1; } } vector<array<lint, 3>> ans; for (auto a : answer) { if (a[0] > a[2]) swap(a[0], a[2]); if (a[1] > a[3]) swap(a[1], a[3]); assert(a[2] - a[0] == a[3] - a[1]); ans.push_back({a[0], a[1], a[2] - a[0]}); } int it = 0; while (int(ans.size()) < K) { ans.push_back({lint(-3e9 + 2 * it), lint(3e9), 1}); it++; } const auto ValidAnswer = [&](vector<array<lint, 3>> sq) { assert(int(sq.size()) <= K); for (int i = 0; i < int(sq.size()); i++) { for (int j = 0; j < int(sq.size()); j++) if (i != j) { for (auto x : {sq[j][0], sq[j][0] + sq[j][2]}) { for (auto y : {sq[j][1], sq[j][1] + sq[j][2]}) { lint minX = sq[i][0]; lint maxX = sq[i][0] + sq[i][2]; lint minY = sq[i][1]; lint maxY = sq[i][1] + sq[i][2]; if (minX <= x && x <= maxX && minY <= y && y <= maxY) { return false; } } } } } for (int i = 0; i < N; i++) { bool found = false; for (auto [x, y, l] : sq) { if (x <= X[i] && X[i] <= x + l && y <= Y[i] && Y[i] <= y + l) { found = true; break; } } if (!found) { return false; } } return true; }; assert(ValidAnswer(ans)); for (int i = 0; i < K; i++) { cout << ans[i][0] << ' ' << ans[i][1] << ' ' << ans[i][2] << '\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...