#include <iostream>
#include <iterator>
#include <memory>
#include <vector>
#include <deque>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
using namespace std;
using StateKey = uint64_t;
inline StateKey pack_state(int walk, int prev) {
return (uint64_t(walk) << 32) | uint32_t(prev);
}
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);
}
auto do_walk = [&](int walk, int prev_walk) {
if (node_edges[walk].empty()) return walk;
int next = node_edges[walk][0];
if (node_edges[walk].size() == 2 && next == prev_walk)
next = node_edges[walk][1];
return next;
};
// Switch to hash-based caches for O(1) amortized lookups
unordered_map<StateKey, int> state_to_path_pos;
unordered_map<StateKey, int> state_to_cycle_start_pos;
unordered_map<StateKey, shared_ptr<deque<pair<int,int>>>> state_to_path_with_cycle;
unordered_set<StateKey> visited;
// Reserve to avoid rehash
state_to_path_pos.reserve(2 * N);
state_to_cycle_start_pos.reserve(2 * N);
state_to_path_with_cycle.reserve(2 * N);
visited.reserve(2 * N);
auto can_from_node = [&](int node, int g) {
auto path = make_shared<deque<pair<int,int>>>();
visited.clear();
int prev = node;
int walk = do_walk(prev, -1);
int next = do_walk(walk, prev);
while (g > 0) {
--g;
StateKey key = pack_state(walk, next);
// Cache hit: compute directly without extra loops
if (state_to_path_pos.count(key)) {
int path_pos = state_to_path_pos[key];
int cycle_start = state_to_cycle_start_pos[key];
auto path_with_cycle = state_to_path_with_cycle[key];
int cycle_len = path_with_cycle->size() - cycle_start;
int g_rem;
if (path_pos >= cycle_start) {
g_rem = g + (path_pos - cycle_start);
} else if (path_pos + g >= cycle_start) {
g_rem = g - (cycle_start - path_pos);
} else {
return (*path_with_cycle)[path_pos + g].first == P;
}
int idx = cycle_start + (g_rem % cycle_len);
return (*path_with_cycle)[idx].first == P;
}
// First time seeing this state
if (!visited.count(key)) {
visited.insert(key);
path->emplace_back(walk, next);
int temp = walk;
walk = do_walk(walk, prev);
if (temp == walk) return walk == P;
prev = temp;
next = do_walk(walk, prev);
} else {
// Found a cycle: cache path positions and cycle start
auto it = find(path->begin(), path->end(), make_pair(walk, next));
int cycle_start = distance(path->begin(), it);
for (int i = 0; i < (int)path->size(); ++i) {
StateKey k = pack_state(path->at(i).first, path->at(i).second);
state_to_path_pos[k] = i;
state_to_cycle_start_pos[k] = cycle_start;
state_to_path_with_cycle[k] = path;
}
int cycle_len = path->size() - cycle_start;
int idx = cycle_start + (g % cycle_len);
return (*path)[idx].first == P;
}
}
// No more steps: check final node
return path->back().first == P;
};
for (int i = 0; i < Q; ++i) {
int g_val = G[i];
int count = 0;
for (int node = 0; node < N; ++node) {
if (can_from_node(node, g_val)) count++;
}
answer(count);
}
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |