Submission #603751

#TimeUsernameProblemLanguageResultExecution timeMemory
603751erekleMechanical Doll (IOI18_doll)C++17
15 / 100
191 ms23172 KiB
#include "doll.h" #include <set> #include <tuple> #include <cassert> #include <iostream> using namespace std; const int INF = 1e9; bool drain(int i, int root, vector<int> &X, vector<int> &Y) { bool isDrain = false; if (X[-i] < 0) {if (drain(X[-i], root, X, Y)) isDrain = true;} else if (X[-i] == 0 || X[-i] == INF) X[-i] = root, isDrain = true; if (Y[-i] < 0) {if (drain(Y[-i], root, X, Y)) isDrain = true;} else if (Y[-i] == 0 || Y[-i] == INF) Y[-i] = root, isDrain = true; return isDrain; } void create_circuit(int M, vector<int> A) { int N = A.size(); vector<vector<int>> nxt(1+M); nxt[0].push_back(A[0]); for (int i = 0; i < N-1; ++i) { nxt[A[i]].push_back(A[i+1]); } nxt[A[N-1]].push_back(0); int S = 0; vector<int> X(1), Y(1); vector<int> C(1+M); // root switch for each trigger for (int i = 0; i <= M; ++i) { if (nxt[i].empty()) { // unused trigger C[i] = i; continue; } int p2 = 1, expo = 0; while (p2 < (int)nxt[i].size()) ++expo, p2 <<= 1; // Order targets (stored in nxt) for tree of switches vector<int> orderedNxt(1, 0); for (int j = 1, previousPow2 = 1; j <= expo; ++j, previousPow2 <<= 1) { vector<int> nextLevel(2*orderedNxt.size()); for (int k = 0; k < (int)nextLevel.size(); ++k) { nextLevel[k] = orderedNxt[k>>1] + (k&1)*previousPow2; } orderedNxt = nextLevel; } for (int j = 0; j < p2; ++j) { if (orderedNxt[j] >= (int)nxt[i].size()) orderedNxt[j] = INF; else orderedNxt[j] = nxt[i][orderedNxt[j]]; } set<pair<pair<int, int>, int>> gotSwitches; // Now build switches for pairs of targets vector<int> curSwitches = orderedNxt; while (curSwitches.size() > 1) { vector<int> nextSwitches((int)curSwitches.size()>>1); for (int j = 0; j < (int)nextSwitches.size(); ++j) { int x = curSwitches[2*j], y = curSwitches[2*j+1]; if (x==INF && y==INF) {// this should never happen nextSwitches[j] = INF; continue; } // create switch auto it = gotSwitches.lower_bound({{x, y}, 0}); if (x != INF && y != INF && it != gotSwitches.end() && it->first.first == x && it->first.second == y) { nextSwitches[j] = -it->second; // Use existing switch } else { // Create new switch since it does not already exist ++S; X.push_back(x); Y.push_back(y); gotSwitches.insert({{x, y}, S}); nextSwitches[j] = -S; } } curSwitches = nextSwitches; } // now curSwitches[0] is the root switch for this trigger C[i] = curSwitches[0]; } // Now we need to "drain" the switches at the end so they all have state X at the end // find the roots of the trees that need draining vector<int> needDrain; for (int i = 0; i <= M; ++i) { if (C[i] >= 0) { if (C[i] == 0 || C[i] == INF) C[i] = i; } else if (drain(C[i], C[i], X, Y) && i != A[N-1]) { needDrain.push_back(i); } } auto getBottom = [&C, &Y](int i) { int root = C[i]; i = C[i]; while (true) { if (i > 0) { if (C[i] == root) return i; i = C[i]; } else { if (Y[-i] == root) return i; i = Y[-i]; } } }; // link up the drain chain drain chain int prevBottom = getBottom(A[N-1]); for (int i : needDrain) { // connect bottom (end) of previous to root of current if (prevBottom > 0) C[prevBottom] = C[i]; else Y[-prevBottom] = C[i]; // find bottom of current prevBottom = getBottom(i); } // connect last bottom back to the origin if (prevBottom > 0) C[prevBottom] = 0; else Y[-prevBottom] = 0; X.erase(X.begin()); Y.erase(Y.begin()); answer(C, X, Y); }
#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...