Submission #438603

#TimeUsernameProblemLanguageResultExecution timeMemory
438603fleimgruberDungeons Game (IOI21_dungeons)C++17
63 / 100
2976 ms737076 KiB
// this solves subtask 1, 3, 4, 5. the complexity is correct, // but for larger n we get MLE. instead of binary lifting, we // should probably use some other base.. #include "dungeons.h" #include <bits/stdc++.h> using namespace std; const int MAX_N = 50001; // subtasks 1, 3, 4, 5 // 2^24 > 10^7 const int MAX_LOG = 25; // ~log_2(10^7) // dp[i][j][k] = we're at i, simulate for 2^j steps and // win against an opponent if strength < 2^k (we don't gain strength) struct { int end; // where do we end up at? long long gained; // total strength gained on the path // max(sum(gained) - opponent) along the simulation, // for all opponents we lose against long long max; } dp[MAX_N][MAX_LOG][MAX_LOG]; int n, s[MAX_N], w[MAX_N]; void init(int n_, vector<int> s_, vector<int> p, vector<int> w_, vector<int> l) { n = n_; copy_n(s_.begin(), n, s); copy_n(w_.begin(), n, w); w[n] = n; for (int j = 0; j < MAX_LOG; j++) for (int i = 0; i <= n; i++) for (int k = 0; k < MAX_LOG; k++) { auto& x = dp[i][j][k]; if (j == 0) if (i == n) { x.end = n; x.gained = x.max = 0; } else if (s[i] < (1 << k)) { // we win x.end = w[i]; x.gained = s[i]; x.max = LLONG_MIN; } else { x.end = l[i]; x.gained = p[i]; // 1 step behind (we didn't gain 'gained' yet) x.max = -s[i]; } else { auto& a = dp[i][j - 1][k]; auto& b = dp[a.end][j - 1][k]; x.end = b.end; x.gained = a.gained + b.gained; x.max = max(a.max, a.gained + b.max); } } } long long simulate(int at, int s_init) { long long strength = s_init; int k = 0; auto advance_k = [&] { // msb if (strength >= (1 << 24)) k = 24; else while ((1 << (k + 1)) <= strength) k++; }; // find first time our dp takes the wrong path. once this happens, // the msb will change => happens only log(something) times // at this vertex we win: // strength + gained - opponent >= 0 // => strength + dp.max >= 0 // but dp loses (dp.max is only calculated for losing edges) auto wrong_turn = [&](int i, int j, int k) { return strength + dp[i][j][k].max >= 0; }; while (at != n) { advance_k(); // jump to point where msb changes for (int j = MAX_LOG - 1; j >= 0; j--) if (!wrong_turn(at, j, k)) { // doesn't change => jump forward auto& x = dp[at][j][k]; at = x.end; strength += x.gained; } // else it changes, so don't jump forward // now wrong_turn(at, 0, k) holds, so we win strength += s[at]; at = w[at]; } return strength; }
#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...