Submission #1217997

#TimeUsernameProblemLanguageResultExecution timeMemory
1217997asturnoxTropical Garden (IOI11_garden)C++20
49 / 100
5096 ms25668 KiB

#include <iostream>
#include <memory>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

void answer(int X);

void count_routes(int N, int M, int P, int R[][2], int Q, int G[]) {
    // Build adjacency lists, but only keep up to 2 edges per node
    vector<vector<int>> node_edges(N + 1);
    for (int idx = 0; idx < M; ++idx) {
        int i = R[idx][0];
        int j = R[idx][1];
        if (node_edges[i].size() < 2) {
            node_edges[i].push_back(j);
        }
        if (node_edges[j].size() < 2) {
            node_edges[j].push_back(i);
        }
    }

    // Walk function: choose the neighbor that's not the one we came from
    auto do_walk = [&](int walk, int prev_walk) {
        if (node_edges[walk].empty()) {
            // No neighbors, same
            return walk;
        }
        int next_walk = node_edges[walk][0];
        if (node_edges[walk].size() == 2 && next_walk == prev_walk) {
            next_walk = node_edges[walk][1];
        }
        return next_walk;
    };

    map<pair<int, int>, shared_ptr<deque<pair<int, int>> >> state_to_cycle;

    // Can we, starting from `node`, after g steps end up at node P?
    auto can_from_node = [&](int node, int g) {
        auto path  = make_shared<deque<pair<int,int>>>();
        set<pair<int,int>> visited;

        int prev_walk = node;
        int walk = do_walk(prev_walk, -1);
        int next_walk = do_walk(walk, prev_walk);  // uses default prev_walk = -1

        while (g > 0) {
            g--;

            pair<int,int> state = make_pair(walk, next_walk);
            if (state_to_cycle.find(state) != state_to_cycle.end()) { // cached
                auto cycle = state_to_cycle[state];
                auto c_size = cycle->size();

                auto it = std::find(cycle->begin(), cycle->end(), state);
                if (it != cycle->end()) {
                    size_t pos = std::distance(cycle->begin(), it);
                    // pos is the index of 'state' in the deque

                    return (*cycle)[(pos + g) % c_size].first == P;
                } else {
                    // std::cout << "ERROR, not in cycle" << std::endl;
                    throw std::runtime_error("State not found in cached cycle");
                }

            }

            if (visited.find(state) == visited.end()) {
                visited.insert(state);
                path->push_back(state);

                int temp = walk;
                walk = do_walk(walk, prev_walk);
                if (temp == walk) {
                    return walk == P; // we are stuck at walk
                }

                prev_walk = temp;
                next_walk = do_walk(walk, prev_walk);
            } else {
                // std::cout << "hit cycle!" << std::endl;
                // std::cout << "g remaining " << g << std::endl;
                // std::cout << "path: " << std::endl;
                for (int i = 0; i < path->size(); i++) {
                    // std::cout << path[i].first << " " << path[i].second << std::endl;
                }

                // std::cout << "state: " << state.first << " " << state.second << std::endl;

                while (path->front() != state) {
                    // std::cout << "popping " << path.front().first << " " << path.front().second << std::endl;
                    path->pop_front();
                }
                // now have a cycle
                for (auto state_it = path->begin(); state_it != path->end(); ++state_it) {
                    // cache
                    state_to_cycle.insert({*state_it, path});
                }
                
                int c = path->size();
                // std::cout << "cycle length " << c << std::endl;
                return (*path)[g % c].first == P;
            }
        }

        // std::cout << "found path:" << '\n';
        for (int i = 0; i < path->size(); i ++) {
            // std::cout << path[i].first << '\n';
        }
        // std::cout << "--------" << '\n';

        // After g steps, are we at P?
        return path->back().first == P;
    };

    for (int i = 0; i < Q; i++) {
        int g_val = G[i];
        int count = 0;
        // std::cout << "i " << i << std::endl;
        for (int node = 0; node < N; ++node) {
            // std::cout << "can from node: " << node << " " << g_val << std::endl;
            bool can = can_from_node(node, g_val);
            // std::cout << "can from node " << node << " " << g_val << ": " << can << std::endl;
            if (can) {
                count++;
            }
            // std::cout << "--------------------" << std::endl;
        }
        answer(count);


        // std::cout << "----------------------------------------" << std::endl;
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...