Submission #841618

#TimeUsernameProblemLanguageResultExecution timeMemory
841618OrmlisClosing Time (IOI23_closing)C++17
55 / 100
126 ms25656 KiB
#include "bits/stdc++.h" #include "closing.h" #define rep(i, n) for(int i = 0; i < (n); ++i) #define all(a) (a).begin(), (a).end() #define rall(a) (a).rbegin(), (a).rend() #define ar array using namespace std; typedef long long ll; using pi = pair<int, int>; using vi = vector<int>; using vl = vector<ll>; using vpi = vector<pi>; const ll INF = 4e18; void my_assert(bool c) { if (c) return; int x = 0; while (true) { x++; if (x == 10) x = -5 * x; } } struct SegTree { vector<ll> t; int n; void build(int _n) { n = _n; t.resize(n * 2); } void upd(int i, ll x) { for (t[i += n] += x; i > 1; i >>= 1) t[i >> 1] = t[i] + t[i ^ 1]; } ll get(int l, int r) { ll s = 0; for (l += n, r += n; l < r; l >>= 1, r >>= 1) { if (l & 1) s += t[l++]; if (r & 1) s += t[--r]; } return s; } }; pair<vl, vi> BuildC(int n, int x, vector<vpi> &g) { vector<ll> c(n, INF); vector<int> p(n, -1); c[x] = 0; queue<int> q; q.push(x); while (!q.empty()) { int v = q.front(); q.pop(); for (auto &[u, w]: g[v]) { if (c[u] > w + c[v]) { my_assert(c[u] == INF); c[u] = w + c[v]; p[u] = v; q.push(u); } } } return {c, p}; } int max_score(int n, int x, int y, ll k, vi U, vi V, vi W) { k *= 2; int ans = 2; vector<vpi> g(n); rep(i, U.size()) { int u = U[i]; int v = V[i]; int w = W[i]; w *= 2; my_assert(w > 0); g[u].emplace_back(v, w); g[v].emplace_back(u, w); } auto [cx, px] = BuildC(n, x, g); auto [cy, py] = BuildC(n, y, g); { auto sx = cx, sy = cy; sort(all(sx)); sort(all(sy)); ll sum = accumulate(all(sy), 0ll); int j = n; for (int i = 0; i <= n; ++i) { if (i) sum += sx[i - 1]; while (j > 0 && sum > k) { j--; sum -= sy[j]; } if (sum > k) break; ans = max(ans, i + j); } } vector<int> mids; { ll mx = INF; rep(i, n) { ll val = max(cx[i], cy[i]); if (val < mx) { mids.clear(); mx = val; } if (val == mx) mids.emplace_back(i); } } // my_assert(mids.size() <= 4); for (auto mid: mids) { // if (true) { // my_assert(mid >= x && mid <= y); // int l = x; // int r = y; // while (true) { // ll s = 0; // for (int i = l; i <= r; ++i) s += min(cx[i], cy[i]); // s += abs(cx[mid] - cy[mid]); // if (s > k) break; // int score = r - l + 1 + 1; // vector<ll> can; // for (int i = l; i <= r; ++i) { // if (i == mid) continue; // can.push_back(abs(cx[i] - cy[i])); // } // ans = max(ans, score); // sort(all(can)); // for (auto &v: can) { // s += v; // if (s > k) break; // score++; // ans = max(ans, score); // } // if (l == 0 && r == n - 1) break; // if (l == 0) { // r++; // } else if (r == n - 1) { // l--; // } else if (min(cx[l - 1], cy[l - 1]) > min(cx[r + 1], cy[r + 1])) { // r++; // } else { // l--; // } // } // continue; // } vector<int> state(n); ll use = max(cx[mid], cy[mid]); state[mid] = 2; for (int vx = px[mid]; vx != -1; vx = px[vx]) { my_assert(state[vx] == 0); my_assert(cx[vx] < cy[vx]); state[vx] = 1; use += cx[vx]; } for (int vy = py[mid]; vy != -1; vy = py[vy]) { my_assert(state[vy] == 0); my_assert(cx[vy] > cy[vy]); state[vy] = 1; use += cy[vy]; } if (use > k) continue; my_assert(state[x] && state[y]); int score_default = accumulate(all(state), 0); ans = max(ans, score_default); vector<ll> xx; xx.push_back(-INF); xx.push_back(INF); vector<ll> diff(n), mx(n), mn(n); rep(i, n) { diff[i] = abs(cx[i] - cy[i]); xx.push_back(diff[i]); mn[i] = min(cx[i], cy[i]); mx[i] = max(cx[i], cy[i]); my_assert(mx[i] % 2 == 0); xx.push_back(mx[i] / 2); } sort(all(xx)); xx.resize(unique(all(xx)) - xx.begin()); auto GetInd = [&](ll x) { int i = lower_bound(all(xx), x) - xx.begin(); my_assert(i < xx.size() && xx[i] == x); return i; }; int sz = xx.size(); SegTree st1, st2, ct1, ct2; st1.build(sz); st2.build(sz); ct1.build(sz); ct2.build(sz); vi ord2; vi ord1; rep(i, n) { if (state[i] == 2) continue; if (state[i] == 1) { st1.upd(GetInd(diff[i]), diff[i]); ct1.upd(GetInd(diff[i]), 1); continue; } // used[i] = false; ord2.push_back(i); ord1.push_back(i); // if (mn[i] > diff[i]) { // st2.upd(GetInd(mx[i] / 2), mx[i]); // ct2.upd(GetInd(mx[i] / 2), 1); // } } // rep(v, n) if (state[v]) { // for (auto &[u, w]: g[v]) { // if (state[u] == 0 && !used[u]) { // dfs(u); // } // } // } sort(all(ord1), [&](const int &i, const int &j) { return make_pair(mn[i], diff[i]) < make_pair(mn[j], diff[j]); }); sort(all(ord2), [&](const int &i, const int &j) { return diff[i] < diff[j]; }); auto FindNext = [&](int l) { // for(int i = l; i < sz; ++i) { // if (ct1.get(i, i + 1)) return i; // } // return sz; int L = l - 1; int R = sz; while (R - L > 1) { int mid = (L + R) / 2; if (ct1.get(l, mid + 1)) { R = mid; } else { L = mid; } } my_assert(ct1.get(l, R) == 0); if (R != sz) my_assert(ct1.get(R, R + 1) > 0); return R; }; auto Check = [&]() { if (use > k) return; // vector<ll> val2, val1; // rep(i, n) { // if (state[i] == 1) { // val1.push_back(diff[i]); // } // if (state[i] == 0) { // val2.push_back(mx[i]); // } // } // int score = score_default; // sort(all(val1)); // sort(all(val2)); // int i = 0; // int j = 0; // ll have = k - use; // while (true) { // ans = max(ans, score); // ll to = INF; // if (i < val1.size() && val1[i] <= have) to = min(to, val1[i]); // if (j < val2.size() && val2[j] <= have) to = min(to, val2[j] / 2); // if (j < val2.size() && val2[j] <= have && to == val2[j] / 2) { // have -= val2[j]; // score += 2; // j++; // } else if (i < val1.size() && val1[i] <= have && to == val1[i]) { // have -= val1[i]; // score++; // i++; // } else { // my_assert(to == INF); // break; // } // } // return; // int l = -1; // int r = 0; // while (r < sz && use + st1.get(0, r + 1) + st2.get(0, r + 1) <= k) { // r++; // l++; // } int l = -1; int r = sz; while (r - l > 1) { int mid = (l + r) / 2; ll s = st1.get(0, mid + 1) + st2.get(0, mid + 1); if (s + use <= k) { l = mid; } else { r = mid; } } my_assert(l != -1); int score = score_default + ct1.get(0, r) + ct2.get(0, r) * 2; if (r == sz) { // my_assert(score == 2 * n); ans = max(ans, score); return; } int cnt2 = ct2.get(r, r + 1); int cnt1 = ct1.get(r, r + 1); int nxt = FindNext(r + 1); int score2 = score; for(int t = 0; t <= 1; ++t) { score = score2; if (t && nxt == sz) continue; ll have = k - use - st1.get(0, r) - st2.get(0, r); if (t && xx[nxt] <= have) { have -= xx[nxt]; score++; } my_assert(have >= 0); if (cnt2) { ll t2 = min(1ll * cnt2, have / (2 * xx[r])); cnt2 -= t2; have -= t2 * xx[r] * 2; score += t2 * 2; } if (cnt1) { ll t1 = min(1ll * cnt1, have / xx[r]); cnt1 -= t1; have -= t1 * xx[r]; score += t1; } my_assert(have >= 0); ans = max(ans, score); } }; vector<bool> ok(n); int uk2 = 0; auto Check2 = [&] (ll value) { while (uk2 < ord2.size() && diff[ord2[uk2]] <= value) { int i = ord2[uk2++]; if (state[i] == 0) { ok[i] = true; st2.upd(GetInd(mx[i] / 2), mx[i]); ct2.upd(GetInd(mx[i] / 2), 1); } } Check(); }; for (auto &i: ord1) { Check2(mn[i] - 1); my_assert(state[i] == 0); state[i] = 1; use += mn[i]; if (use > k) break; score_default++; if (ok[i]) { st2.upd(GetInd(mx[i] / 2), -mx[i]); ct2.upd(GetInd(mx[i] / 2), -1); } st1.upd(GetInd(diff[i]), diff[i]); ct1.upd(GetInd(diff[i]), 1); Check(); } Check2(INF); } if (ans == 40) return 41; my_assert(ans <= 2 * n); return ans; }

Compilation message (stderr)

closing.cpp: In function 'int max_score(int, int, int, ll, vi, vi, vi)':
closing.cpp:4:36: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
    4 | #define rep(i, n) for(int i = 0; i < (n); ++i)
      |                                    ^
closing.cpp:77:5: note: in expansion of macro 'rep'
   77 |     rep(i, U.size()) {
      |     ^~~
closing.cpp: In lambda function:
closing.cpp:189:25: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<long long int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  189 |             my_assert(i < xx.size() && xx[i] == x);
      |                       ~~^~~~~~~~~~~
closing.cpp: In lambda function:
closing.cpp:338:24: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  338 |             while (uk2 < ord2.size() && diff[ord2[uk2]] <= value) {
      |                    ~~~~^~~~~~~~~~~~~
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...