Submission #405812

#TimeUsernameProblemLanguageResultExecution timeMemory
405812534351The short shank; Redemption (BOI21_prison)C++17
80 / 100
2028 ms163744 KiB
#include <bits/stdc++.h> using namespace std; template<class T, class U> void ckmin(T &a, U b) { if (a > b) a = b; } template<class T, class U> void ckmax(T &a, U b) { if (a < b) a = b; } #define MP make_pair #define PB push_back #define LB lower_bound #define UB upper_bound #define fi first #define se second #define FOR(i, a, b) for (auto i = (a); i < (b); i++) #define FORD(i, a, b) for (auto i = (a) - 1; i >= (b); i--) #define SZ(x) ((int) (x).size()) #define ALL(x) (x).begin(), (x).end() const int MAXN = 2100013; const long long LLINF = 3e18; typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef vector<int> vi; typedef vector<ll> vl; typedef vector<pii> vpi; typedef vector<pll> vpl; int N, D, T; int arr[MAXN], lt[MAXN]; int fen[MAXN]; ll dp[MAXN]; int cost[MAXN], taken[MAXN]; int ans; void update(int idx, int v) { for (int e = idx + 1; e <= N; e += e & (-e)) { ckmax(fen[e], v); } } int query(int idx) { int res = -1; for (int e = idx + 1; e; e -= e & (-e)) { ckmax(res, fen[e]); } return res; } //maintain a segment tree of (dp, best dp) pll seg[2 * MAXN]; //store (min, argmin) ll lazy[2 * MAXN]; void build(int w, int L, int R) { if (L == R) { seg[w] = {LLINF, L}; lazy[w] = 0; return; } int mid = (L + R) >> 1; build(w << 1, L, mid); build(w << 1 | 1, mid + 1, R); seg[w] = min(seg[w << 1], seg[w << 1 | 1]); lazy[w] = 0; } void push(int w, int L, int R) { if (lazy[w] == 0) return; seg[w].fi += lazy[w]; if (L != R) { lazy[w << 1] += lazy[w]; lazy[w << 1 | 1] += lazy[w]; } lazy[w] = 0; return; } void update(int w, int L, int R, int a, int b, ll v) { push(w, L, R); if (b < L || R < a) return; if (a <= L && R <= b) { lazy[w] += v; push(w, L, R); return; } int mid = (L + R) >> 1; update(w << 1, L, mid, a, b, v); update(w << 1 | 1, mid + 1, R, a, b, v); seg[w] = min(seg[w << 1], seg[w << 1 | 1]); } void check(int c) { // cerr << "CHECKING " << c << endl; //assign a penalty of c for starting a new range at c. //minimum # of guys rebelling. build(1, 0, N); dp[0] = 0; taken[0] = 0; update(1, 0, N, 0, 0, -LLINF); // fill(cost, cost + N + 1, 0); FOR(i, 0, N) { int v = lt[i]; update(1, 0, N, 0, v, 1); // FOR(j, 0, v + 1) // { // cost[j]++; // } // FOR(j, 0, i + 1) // { // if (dp[i + 1] > dp[j] + cost[j] + c) // { // dp[i + 1] = dp[j] + cost[j] + c; // taken[i + 1] = taken[j] + 1; // } // } dp[i + 1] = seg[1].fi + c; taken[i + 1] = taken[seg[1].se] + 1; update(1, 0, N, i + 1, i + 1, -LLINF + dp[i + 1]); // cerr << dp[i + 1] << ' ' << taken[i + 1] << endl; } // cerr << "DP " << dp[N] << " TAKEN " << c << endl; return; } int32_t main() { ios_base::sync_with_stdio(false); cin.tie(0); cout << fixed << setprecision(12); cerr << fixed << setprecision(4); cin >> N >> D >> T; D++; FOR(i, 0, N) { cin >> arr[i]; } fill(fen, fen + N + 1, -1); FOR(i, 0, N) { int c = arr[i]; if (c <= T) { //i...i+(T-c) are getting infected. update(max(0, N - 1 - (i + (T - c))), i); } lt[i] = query(N - 1 - i); // cerr << lt[i] << ' '; } if (D == 2) { FOR(i, 0, N) { int v = lt[i]; // cerr << v << endl; //it will rebel if: //v != -1 //the block is in 0...v-1 or i...N-1 if (v != -1) { cost[0]++; cost[v]--; cost[i]++; cost[N]--; } } FOR(i, 0, N) { cost[i + 1] += cost[i]; } ans = N; FOR(i, 0, N - 1) { ckmin(ans, cost[i]); } cout << ans << '\n'; return 0; } int lo = 0, hi = N + 1; while(hi > lo) { int mid = (hi + lo + 1) >> 1; check(mid); if (taken[N] >= D) lo = mid; else hi = mid - 1; } // cerr << "LO = " << lo << endl; check(lo); // cerr << "TAKED " << taken[N] << endl; ll cost1 = dp[N] - lo * taken[N]; int cnt1 = taken[N]; assert(cnt1 >= D); if (cnt1 == D) { ans = cost1; } else { hi++; check(hi); ll cost2 = dp[N] - hi * taken[N]; int cnt2 = taken[N]; assert(cnt2 < D); // cerr << cost1 << ' ' << cnt1 << ' ' << cost2 << ' ' << cnt2 << endl; ans = cost2 + (cost1 - cost2) * (D - cnt2) / (cnt1 - cnt2); } cout << ans << '\n'; //you are going to have some new blocks starting with -1....x. and then -1...x and then -1...x // cerr << endl; 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...