Submission #438593

#TimeUsernameProblemLanguageResultExecution timeMemory
438593fleimgruberDungeons Game (IOI21_dungeons)C++17
63 / 100
2887 ms738520 KiB
#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 DP { 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_; for (int i = 0; i < n; i++) { s[i] = s_[i]; w[i] = w_[i]; } 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; continue; } 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 = [&] { // lsb 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 lsb will change => happens only log(something) times // at this vertex we win: // strength + gained - opponent >= 0 // => strength + max(sum(gained) - opponent) >= 0 // but strength_max >= 2^k (i.e. dp doesn't win) 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 lsb 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...