提出 #76878850
ソースコード 拡げる
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define reps(i, a, n) for (int i = (a); i < (int)(n); ++i)
const int INF = 1e9;
struct Door {
int a = -1;
int b = -1;
int g = -1;
};
struct PlacedSwitch {
int v = -1;
int s = -1;
};
struct Layout {
vector<int> switch_index;
vector<int> gate_edge_index;
};
struct SidePath {
int main_index = -1;
int first_vertex = -1;
vector<int> path;
};
struct Candidate {
vector<Door> doors;
vector<PlacedSwitch> switches;
vector<int> main_path;
vector<int> path_a;
vector<int> path_b;
vector<int> path_c;
set<int> skeleton_edges;
int index_a = -1;
int index_b = -1;
int fixed_wall_count = 0;
int full_isolation_wall_count = 0;
int theoretical_t = -1;
int selection_score = -1;
int exact_t = -1;
bool valid = false;
};
struct GraphEdge {
int u = -1;
int v = -1;
};
struct TreeState {
vector<char> in_tree;
vector<vector<int>> tree_adj;
Candidate best_raw_candidate;
int score = -INF;
bool valid = false;
};
struct Solver {
static constexpr double RANDOM_END_MS = 400.0;
static constexpr double ANNEAL_END_MS = 1350.0;
static constexpr double EXACT_END_MS = 1900.0;
static constexpr int SA_SEED_COUNT = 4;
static constexpr int RAW_POOL_LIMIT = 100;
static constexpr int EXACT_CANDIDATE_LIMIT = 50;
static constexpr int SA_EXCESS_WALL_PENALTY = 2;
int N = 0;
int M = 0;
int K = 0;
vector<string> c;
vector<vector<int>> adj;
vector<GraphEdge> all_edges;
vector<vector<int>> edge_id;
vector<uint64_t> edge_zobrist;
vector<int> deg;
vector<int> open_cells;
uint64_t board_hash = 0;
chrono::steady_clock::time_point start_time;
long long generated_tree_count = 0;
long long generated_side_path_count = 0;
long long examined_pair_count = 0;
long long detailed_pair_count = 0;
long long valid_candidate_count = 0;
long long exact_evaluated_count = 0;
long long generated_raw_candidate_count = 0;
long long lazy_repair_attempt_count = 0;
long long lazy_repair_success_count = 0;
mutable long long exact_bfs_count = 0;
long long random_phase_tree_count = 0;
long long sa_iteration_count = 0;
long long sa_valid_neighbor_count = 0;
long long sa_accepted_count = 0;
long long sa_worse_accepted_count = 0;
long long sa_rejected_count = 0;
long long sa_best_update_count = 0;
int sa_initial_best_score = -INF;
int sa_final_best_score = -INF;
vector<string> repair_logs;
int id(int r, int col) const {
return r * N + col;
}
pair<int, int> rc(int v) const {
return {v / N, v % N};
}
int start_id() const {
return 0;
}
int goal_id() const {
return N * N - 1;
}
bool is_open_cell(int v) const {
auto [r, col] = rc(v);
return 0 <= r && r < N && 0 <= col && col < N && c[r][col] == '.';
}
int edge_key(int a, int b) const {
if (a > b) swap(a, b);
return a * N * N + b;
}
Door make_door(int a, int b, int g) const {
return Door{a, b, g};
}
double elapsed_ms() const {
auto now = chrono::steady_clock::now();
return chrono::duration_cast<chrono::microseconds>(now - start_time).count() / 1000.0;
}
void read_input() {
cin >> N >> M >> K;
c.resize(N);
rep(i, N) cin >> c[i];
board_hash = 1469598103934665603ULL;
rep(i, N) {
for (char ch : c[i]) {
board_hash ^= (uint64_t)(unsigned char)ch;
board_hash *= 1099511628211ULL;
}
}
}
void build_graph() {
adj.assign(N * N, {});
edge_id.assign(N * N, vector<int>(N * N, -1));
all_edges.clear();
deg.assign(N * N, 0);
open_cells.clear();
const int dr[4] = {-1, 1, 0, 0};
const int dc[4] = {0, 0, -1, 1};
rep(r, N) rep(col, N) {
if (c[r][col] == '#') continue;
int v = id(r, col);
open_cells.push_back(v);
rep(dir, 4) {
int nr = r + dr[dir];
int nc = col + dc[dir];
if (0 <= nr && nr < N && 0 <= nc && nc < N && c[nr][nc] == '.') {
adj[v].push_back(id(nr, nc));
}
}
deg[v] = (int)adj[v].size();
}
rep(v, N * N) {
for (int to : adj[v]) {
if (v < to) {
int eid = (int)all_edges.size();
all_edges.push_back({v, to});
edge_id[v][to] = edge_id[to][v] = eid;
}
}
}
edge_zobrist.assign(all_edges.size(), 0);
uint64_t z = board_hash ^ 0x9e3779b97f4a7c15ULL;
rep(i, (int)all_edges.size()) {
z ^= z << 7;
z ^= z >> 9;
z *= 11995408973635179863ULL;
edge_zobrist[i] = z;
}
}
bool make_layout(int edge_len, int switch_count, Layout& layout) const {
if (edge_len < switch_count) return false;
layout.switch_index.assign(switch_count, 0);
layout.gate_edge_index.assign(max(0, switch_count - 1), 0);
rep(t, switch_count) {
layout.switch_index[t] = edge_len - (switch_count - 1 - t);
}
rep(t, switch_count - 1) {
layout.gate_edge_index[t] = layout.switch_index[t + 1] - 1;
if (layout.gate_edge_index[t] < 0) return false;
}
return true;
}
bool make_before_gate_layout(int edge_len, int switch_count, Layout& layout) const {
if (edge_len < switch_count) return false;
layout.switch_index.assign(switch_count, 0);
layout.gate_edge_index.assign(switch_count, 0);
rep(t, switch_count) {
layout.switch_index[t] = edge_len - (switch_count - 1 - t);
layout.gate_edge_index[t] = layout.switch_index[t] - 1;
if (layout.gate_edge_index[t] < 0) return false;
}
return true;
}
vector<int> choose_c_gate_edges(int edge_len) const {
if (edge_len < 9) return {};
vector<int> edges;
rep(i, 8) edges.push_back(i);
edges.push_back(edge_len - 1);
rep(i, (int)edges.size() - 1) {
if (edges[i] >= edges[i + 1]) return {};
}
return edges;
}
void add_path_edges(const vector<int>& path, set<int>& edges) const {
rep(i, (int)path.size() - 1) edges.insert(edge_key(path[i], path[i + 1]));
}
void add_path_vertices(const vector<int>& path, vector<char>& used) const {
for (int v : path) used[v] = 1;
}
void add_gate_door(vector<Door>& doors, const vector<int>& path, int edge_index, int type) const {
doors.push_back(make_door(path[edge_index], path[edge_index + 1], type));
}
uint64_t path_hash(const vector<int>& path) const {
uint64_t h = 1469598103934665603ULL;
for (int v : path) {
h ^= (uint64_t)(v + 1009);
h *= 1099511628211ULL;
}
return h;
}
uint64_t candidate_hash(const Candidate& cand) const {
uint64_t h = path_hash(cand.main_path);
h ^= path_hash(cand.path_a) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
h ^= path_hash(cand.path_b) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);
h ^= (uint64_t)(cand.index_a + 10007) * 1000003ULL;
h ^= (uint64_t)(cand.index_b + 10009) * 9176ULL;
return h;
}
vector<int> make_prefix_lengths(int full_length, int minimum_length) const {
vector<int> vals;
if (full_length < minimum_length) return vals;
vector<int> raw = {
full_length,
full_length - 2,
full_length - 4,
full_length - 6,
full_length - 8,
full_length - 12,
(full_length * 3) / 4,
minimum_length
};
for (int v : raw) {
if (minimum_length <= v && v <= full_length) vals.push_back(v);
}
sort(vals.begin(), vals.end(), greater<int>());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
return vals;
}
vector<vector<int>> generate_random_tree(mt19937& rng) const {
vector<vector<int>> shuffled = adj;
for (int v : open_cells) shuffle(shuffled[v].begin(), shuffled[v].end(), rng);
vector<vector<int>> tree(N * N);
vector<char> visited(N * N, 0);
int root = open_cells[(int)(rng() % open_cells.size())];
vector<pair<int, int>> st;
st.push_back({root, 0});
visited[root] = 1;
int seen = 1;
while (!st.empty()) {
int v = st.back().first;
int& it = st.back().second;
if (it == (int)shuffled[v].size()) {
st.pop_back();
continue;
}
int to = shuffled[v][it++];
if (visited[to]) continue;
visited[to] = 1;
++seen;
tree[v].push_back(to);
tree[to].push_back(v);
st.push_back({to, 0});
}
if (seen != (int)open_cells.size()) return {};
return tree;
}
TreeState generate_random_tree_state(mt19937& rng) const {
TreeState state;
state.in_tree.assign(all_edges.size(), 0);
state.tree_adj.assign(N * N, {});
vector<vector<int>> shuffled = adj;
for (int v : open_cells) shuffle(shuffled[v].begin(), shuffled[v].end(), rng);
vector<char> visited(N * N, 0);
int root = open_cells[(int)(rng() % open_cells.size())];
vector<pair<int, int>> st;
st.push_back({root, 0});
visited[root] = 1;
int seen = 1;
int tree_edges = 0;
while (!st.empty()) {
int v = st.back().first;
int& it = st.back().second;
if (it == (int)shuffled[v].size()) {
st.pop_back();
continue;
}
int to = shuffled[v][it++];
if (visited[to]) continue;
int eid = edge_id[v][to];
if (eid < 0) continue;
visited[to] = 1;
++seen;
++tree_edges;
state.in_tree[eid] = 1;
state.tree_adj[v].push_back(to);
state.tree_adj[to].push_back(v);
st.push_back({to, 0});
}
if (seen != (int)open_cells.size() || tree_edges != (int)open_cells.size() - 1) {
state.valid = false;
return state;
}
state.valid = true;
return state;
}
uint64_t tree_hash(const TreeState& state) const {
uint64_t h = 0;
rep(eid, (int)state.in_tree.size()) {
if (state.in_tree[eid]) h ^= edge_zobrist[eid];
}
return h;
}
void add_tree_edge(TreeState& state, int eid) const {
if (eid < 0 || eid >= (int)all_edges.size()) return;
if (state.in_tree[eid]) return;
int u = all_edges[eid].u;
int v = all_edges[eid].v;
state.in_tree[eid] = 1;
state.tree_adj[u].push_back(v);
state.tree_adj[v].push_back(u);
}
void remove_tree_edge(TreeState& state, int eid) const {
if (eid < 0 || eid >= (int)all_edges.size()) return;
if (!state.in_tree[eid]) return;
int u = all_edges[eid].u;
int v = all_edges[eid].v;
state.in_tree[eid] = 0;
auto erase_one = [](vector<int>& xs, int value) {
auto it = find(xs.begin(), xs.end(), value);
if (it != xs.end()) xs.erase(it);
};
erase_one(state.tree_adj[u], v);
erase_one(state.tree_adj[v], u);
}
vector<int> get_tree_path_edge_ids(const vector<vector<int>>& tree_adj, int src, int dst) const {
vector<int> parent(N * N, -1), parent_edge(N * N, -1);
queue<int> que;
parent[src] = src;
que.push(src);
while (!que.empty()) {
int v = que.front();
que.pop();
if (v == dst) break;
for (int to : tree_adj[v]) {
if (parent[to] != -1) continue;
parent[to] = v;
parent_edge[to] = edge_id[v][to];
que.push(to);
}
}
if (parent[dst] == -1) return {};
vector<int> path_edges;
for (int v = dst; v != src; v = parent[v]) path_edges.push_back(parent_edge[v]);
reverse(path_edges.begin(), path_edges.end());
return path_edges;
}
int choose_add_edge(const TreeState& state, mt19937& rng) const {
rep(attempt, 60) {
int eid = (int)(rng() % all_edges.size());
if (!state.in_tree[eid]) return eid;
}
return -1;
}
vector<int> tree_path(const vector<vector<int>>& tree, int src, int dst) const {
vector<int> parent(N * N, -1);
queue<int> que;
parent[src] = src;
que.push(src);
while (!que.empty()) {
int v = que.front();
que.pop();
if (v == dst) break;
for (int to : tree[v]) {
if (parent[to] != -1) continue;
parent[to] = v;
que.push(to);
}
}
if (parent[dst] == -1) return {};
vector<int> path;
for (int v = dst; v != src; v = parent[v]) path.push_back(v);
path.push_back(src);
reverse(path.begin(), path.end());
return path;
}
vector<SidePath> collect_side_paths(const vector<vector<int>>& tree,
const vector<int>& main_path,
const vector<int>& main_index) {
vector<SidePath> sides;
vector<char> on_main(N * N, 0);
for (int v : main_path) on_main[v] = 1;
rep(i, (int)main_path.size()) {
int root = main_path[i];
int prev_main = (i > 0 ? main_path[i - 1] : -1);
int next_main = (i + 1 < (int)main_path.size() ? main_path[i + 1] : -1);
for (int first : tree[root]) {
if (first == prev_main || first == next_main) continue;
if (on_main[first]) continue;
vector<int> parent(N * N, -1), dist(N * N, -1);
queue<int> que;
parent[first] = root;
dist[first] = 1;
que.push(first);
int far = first;
while (!que.empty()) {
int v = que.front();
que.pop();
if (dist[v] > dist[far]) far = v;
for (int to : tree[v]) {
if (to == parent[v] || on_main[to]) continue;
parent[to] = v;
dist[to] = dist[v] + 1;
que.push(to);
}
}
vector<int> path;
for (int v = far; v != root; v = parent[v]) path.push_back(v);
path.push_back(root);
reverse(path.begin(), path.end());
if ((int)path.size() >= 2) {
sides.push_back(SidePath{i, first, path});
}
}
}
(void)main_index;
generated_side_path_count += (long long)sides.size();
return sides;
}
int theoretical_time(const Candidate& cand, const Layout& layout_a, const Layout& layout_b) const {
vector<int> a_dist(5), b_dist(4);
rep(i, 5) a_dist[i] = layout_a.switch_index[i];
rep(i, 4) b_dist[i] = layout_b.switch_index[i];
struct Pos {
int side;
int idx;
};
vector<Pos> seq = {
{0, 0}, {1, 0}, {0, 1}, {1, 1}, {0, 2}, {1, 2}, {0, 3}, {1, 3}, {0, 4},
{1, 3}, {0, 3}, {1, 2}, {0, 2}, {1, 1}, {0, 1}, {1, 0}, {0, 0}
};
auto main_pos = [&](const Pos& p) {
return p.side == 0 ? cand.index_a : cand.index_b;
};
auto branch_dist = [&](const Pos& p) {
return p.side == 0 ? a_dist[p.idx] : b_dist[p.idx];
};
int main_edges = (int)cand.main_path.size() - 1;
long long total = cand.index_a + a_dist[0];
reps(i, 1, (int)seq.size()) {
total += branch_dist(seq[i - 1]);
total += abs(main_pos(seq[i - 1]) - main_pos(seq[i]));
total += branch_dist(seq[i]);
}
total += a_dist[0] + (main_edges - cand.index_a);
total += 17;
return (int)total;
}
bool build_candidate(const vector<int>& main_path,
const SidePath& side_a,
const SidePath& side_b,
int len_a,
int len_b,
Candidate& cand) const {
if (len_a < 5 || len_b < 4) return false;
if ((int)side_a.path.size() <= len_a || (int)side_b.path.size() <= len_b) return false;
int index_a = side_a.main_index;
int index_b = side_b.main_index;
int hi = max(index_a, index_b);
int c_len = (int)main_path.size() - 1 - hi;
if (c_len < 9) return false;
if (index_a == index_b && side_a.first_vertex == side_b.first_vertex) return false;
cand = Candidate{};
cand.main_path = main_path;
cand.index_a = index_a;
cand.index_b = index_b;
cand.path_a.assign(side_a.path.begin(), side_a.path.begin() + len_a + 1);
cand.path_b.assign(side_b.path.begin(), side_b.path.begin() + len_b + 1);
cand.path_c.assign(main_path.begin() + hi, main_path.end());
set<int> skeleton_edges;
vector<char> skeleton_vertices(N * N, 0);
add_path_edges(cand.main_path, skeleton_edges);
add_path_edges(cand.path_a, skeleton_edges);
add_path_edges(cand.path_b, skeleton_edges);
add_path_vertices(cand.main_path, skeleton_vertices);
add_path_vertices(cand.path_a, skeleton_vertices);
add_path_vertices(cand.path_b, skeleton_vertices);
cand.skeleton_edges = skeleton_edges;
set<int> fixed_edges;
rep(v, N * N) {
if (!skeleton_vertices[v]) continue;
for (int to : adj[v]) {
int ek = edge_key(v, to);
if (!skeleton_edges.count(ek)) fixed_edges.insert(ek);
}
}
Layout layout_a, layout_b;
if (!make_layout(len_a, 5, layout_a)) return false;
if (!make_before_gate_layout(len_b, 4, layout_b)) return false;
vector<int> c_gate_edges = choose_c_gate_edges(c_len);
if (c_gate_edges.empty()) return false;
cand.doors.clear();
rep(i, 4) add_gate_door(cand.doors, cand.path_a, layout_a.gate_edge_index[i], 4 * (i + 1) + 1);
rep(i, 4) add_gate_door(cand.doors, cand.path_b, layout_b.gate_edge_index[i], 4 * i + 3);
rep(i, 8) add_gate_door(cand.doors, cand.path_c, c_gate_edges[i], 2 * (i + 1));
add_gate_door(cand.doors, cand.path_c, c_gate_edges.back(), 19);
cand.fixed_wall_count = 0;
cand.full_isolation_wall_count = (int)fixed_edges.size();
if ((int)cand.doors.size() > M) return false;
rep(i, 5) cand.switches.push_back({cand.path_a[layout_a.switch_index[i]], 2 * i + 1});
rep(i, 4) cand.switches.push_back({cand.path_b[layout_b.switch_index[i]], 2 * (i + 1)});
cand.theoretical_t = theoretical_time(cand, layout_a, layout_b);
cand.selection_score = cand.theoretical_t - SA_EXCESS_WALL_PENALTY * max(0, cand.full_isolation_wall_count - 33);
cand.valid = validate_candidate(cand);
return cand.valid;
}
void keep_top_candidate(vector<Candidate>& top_candidates,
set<uint64_t>& seen,
Candidate cand,
int keep_count) const {
uint64_t h = candidate_hash(cand);
if (!seen.insert(h).second) return;
top_candidates.push_back(std::move(cand));
sort(top_candidates.begin(), top_candidates.end(), [](const Candidate& lhs, const Candidate& rhs) {
if (lhs.selection_score != rhs.selection_score) return lhs.selection_score > rhs.selection_score;
return lhs.theoretical_t > rhs.theoretical_t;
});
if ((int)top_candidates.size() > keep_count) top_candidates.resize(keep_count);
}
void process_tree(const vector<vector<int>>& tree,
vector<Candidate>& top_candidates,
set<uint64_t>& seen_candidates) {
vector<int> main_path = tree_path(tree, start_id(), goal_id());
if (main_path.empty()) return;
vector<int> main_index(N * N, -1);
rep(i, (int)main_path.size()) main_index[main_path[i]] = i;
vector<SidePath> sides = collect_side_paths(tree, main_path, main_index);
if ((int)sides.size() < 2) return;
struct PairUpper {
int score = 0;
int x = -1;
int y = -1;
};
vector<PairUpper> pairs;
int main_edges = (int)main_path.size() - 1;
rep(i, (int)sides.size()) reps(j, i + 1, (int)sides.size()) {
++examined_pair_count;
const SidePath& x = sides[i];
const SidePath& y = sides[j];
if (x.main_index == y.main_index && x.first_vertex == y.first_vertex) continue;
int lo = min(x.main_index, y.main_index);
int hi = max(x.main_index, y.main_index);
int c_len = main_edges - hi;
if (c_len < 9) continue;
int len_x = (int)x.path.size() - 1;
int len_y = (int)y.path.size() - 1;
int len_a = max(len_x, len_y);
int len_b = min(len_x, len_y);
if (len_a < 5 || len_b < 4) continue;
int stem_len = lo;
int connector_len = hi - lo;
int rough = stem_len + 17 * connector_len + c_len + 18 * len_a + 16 * len_b;
pairs.push_back({rough, i, j});
}
sort(pairs.begin(), pairs.end(), [](const PairUpper& lhs, const PairUpper& rhs) {
return lhs.score > rhs.score;
});
if ((int)pairs.size() > 200) pairs.resize(200);
for (const PairUpper& pu : pairs) {
const SidePath& x = sides[pu.x];
const SidePath& y = sides[pu.y];
vector<pair<const SidePath*, const SidePath*>> assignments = {{&x, &y}, {&y, &x}};
for (auto [pa, pb] : assignments) {
vector<int> a_lengths = make_prefix_lengths((int)pa->path.size() - 1, 5);
vector<int> b_lengths = make_prefix_lengths((int)pb->path.size() - 1, 4);
for (int la : a_lengths) for (int lb : b_lengths) {
++detailed_pair_count;
Candidate cand;
if (!build_candidate(main_path, *pa, *pb, la, lb, cand)) continue;
++generated_raw_candidate_count;
++valid_candidate_count;
keep_top_candidate(top_candidates, seen_candidates, std::move(cand), 60);
}
}
}
}
vector<int> make_fast_prefix_lengths(int full_length, int minimum_length) const {
vector<int> vals;
if (full_length < minimum_length) return vals;
vector<int> raw = {full_length, full_length - 4, full_length - 8, minimum_length};
for (int v : raw) {
if (minimum_length <= v && v <= full_length) vals.push_back(v);
}
sort(vals.begin(), vals.end(), greater<int>());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
return vals;
}
bool evaluate_tree_fast(const vector<vector<int>>& tree,
Candidate& best_candidate,
int& best_score) {
best_score = -INF;
vector<int> main_path = tree_path(tree, start_id(), goal_id());
if (main_path.empty()) return false;
vector<int> main_index(N * N, -1);
rep(i, (int)main_path.size()) main_index[main_path[i]] = i;
vector<SidePath> sides = collect_side_paths(tree, main_path, main_index);
if ((int)sides.size() < 2) return false;
struct PairUpper {
int score = 0;
int x = -1;
int y = -1;
};
vector<PairUpper> pairs;
int main_edges = (int)main_path.size() - 1;
rep(i, (int)sides.size()) reps(j, i + 1, (int)sides.size()) {
++examined_pair_count;
const SidePath& x = sides[i];
const SidePath& y = sides[j];
if (x.main_index == y.main_index && x.first_vertex == y.first_vertex) continue;
int lo = min(x.main_index, y.main_index);
int hi = max(x.main_index, y.main_index);
int c_len = main_edges - hi;
if (c_len < 9) continue;
int len_x = (int)x.path.size() - 1;
int len_y = (int)y.path.size() - 1;
int len_a = max(len_x, len_y);
int len_b = min(len_x, len_y);
if (len_a < 5 || len_b < 4) continue;
int stem_len = lo;
int connector_len = hi - lo;
int rough = stem_len + 17 * connector_len + c_len + 18 * len_a + 16 * len_b;
pairs.push_back({rough, i, j});
}
if (pairs.empty()) return false;
sort(pairs.begin(), pairs.end(), [](const PairUpper& lhs, const PairUpper& rhs) {
return lhs.score > rhs.score;
});
if ((int)pairs.size() > 40) pairs.resize(40);
for (const PairUpper& pu : pairs) {
const SidePath& x = sides[pu.x];
const SidePath& y = sides[pu.y];
vector<pair<const SidePath*, const SidePath*>> assignments = {{&x, &y}, {&y, &x}};
for (auto [pa, pb] : assignments) {
vector<int> a_lengths = make_fast_prefix_lengths((int)pa->path.size() - 1, 5);
vector<int> b_lengths = make_fast_prefix_lengths((int)pb->path.size() - 1, 4);
for (int la : a_lengths) for (int lb : b_lengths) {
++detailed_pair_count;
Candidate cand;
if (!build_candidate(main_path, *pa, *pb, la, lb, cand)) continue;
++generated_raw_candidate_count;
++valid_candidate_count;
if (cand.selection_score > best_score) {
best_score = cand.selection_score;
best_candidate = std::move(cand);
}
}
}
}
return best_score > -INF;
}
int door_type_between(const vector<vector<int>>& door_h,
const vector<vector<int>>& door_v,
int a,
int b) const {
auto [ar, ac] = rc(a);
auto [br, bc] = rc(b);
if (ar == br) return door_v[ar][min(ac, bc)];
return door_h[min(ar, br)][ac];
}
struct EvalResult {
int shortest_time = 0;
vector<int> route_states;
};
EvalResult calc_T_with_route(const Candidate& cand, bool restore_route) const {
++exact_bfs_count;
vector<vector<int>> door_h(N - 1, vector<int>(N, -1));
vector<vector<int>> door_v(N, vector<int>(N - 1, -1));
for (const Door& door : cand.doors) {
auto [ar, ac] = rc(door.a);
auto [br, bc] = rc(door.b);
if (ar == br) door_v[ar][min(ac, bc)] = door.g;
else door_h[min(ar, br)][ac] = door.g;
}
vector<int> sw(N * N, -1);
for (const PlacedSwitch& s : cand.switches) sw[s.v] = s.s;
auto is_open_door = [](int g, int mask) {
if (g == -1) return true;
int k = g / 2;
return ((mask >> k) & 1) == (g & 1);
};
const int V = N * N;
const int state_count = (1 << K) * V;
vector<int> dist(state_count, -1);
vector<int> parent;
if (restore_route) parent.assign(state_count, -2);
queue<int> que;
dist[start_id()] = 0;
if (restore_route) parent[start_id()] = -1;
que.push(start_id());
while (!que.empty()) {
int state = que.front();
que.pop();
int mask = state / V;
int v = state % V;
int d = dist[state];
if (v == goal_id()) {
EvalResult result;
result.shortest_time = d;
if (restore_route) {
for (int cur = state; cur != -1; cur = parent[cur]) result.route_states.push_back(cur);
reverse(result.route_states.begin(), result.route_states.end());
}
return result;
}
for (int to : adj[v]) {
int g = door_type_between(door_h, door_v, v, to);
if (!is_open_door(g, mask)) continue;
int ns = mask * V + to;
if (dist[ns] == -1) {
dist[ns] = d + 1;
if (restore_route) parent[ns] = state;
que.push(ns);
}
}
if (sw[v] != -1) {
int nmask = mask ^ (1 << sw[v]);
int ns = nmask * V + v;
if (dist[ns] == -1) {
dist[ns] = d + 1;
if (restore_route) parent[ns] = state;
que.push(ns);
}
}
}
return EvalResult{};
}
int calc_T(const Candidate& cand) const {
return calc_T_with_route(cand, false).shortest_time;
}
bool has_door_on_edge(const Candidate& cand, int ek) const {
for (const Door& door : cand.doors) {
if (edge_key(door.a, door.b) == ek) return true;
}
return false;
}
Door find_first_non_skeleton_edge(const Candidate& cand, const vector<int>& route_states) const {
const int V = N * N;
reps(i, 1, (int)route_states.size()) {
int prev_v = route_states[i - 1] % V;
int next_v = route_states[i] % V;
if (prev_v == next_v) continue;
int ek = edge_key(prev_v, next_v);
if (!cand.skeleton_edges.count(ek)) return make_door(prev_v, next_v, 1);
}
return Door{};
}
bool add_fixed_wall(Candidate& cand, int a, int b) const {
bool adjacent = false;
for (int to : adj[a]) {
if (to == b) adjacent = true;
}
if (!adjacent) return false;
int ek = edge_key(a, b);
if (cand.skeleton_edges.count(ek)) return false;
if (has_door_on_edge(cand, ek)) return false;
if (cand.fixed_wall_count >= 33) return false;
if ((int)cand.doors.size() >= M) return false;
cand.doors.push_back(make_door(a, b, 1));
++cand.fixed_wall_count;
return true;
}
bool lazy_repair_candidate(const Candidate& raw, Candidate& repaired, double deadline_ms) {
Candidate cand = raw;
int first_t = -1;
for (int fixed = 0; fixed <= 33; ++fixed) {
EvalResult result = calc_T_with_route(cand, true);
if (elapsed_ms() >= deadline_ms) return false;
if (first_t == -1) first_t = result.shortest_time;
if (result.shortest_time <= 0) return false;
Door shortcut = find_first_non_skeleton_edge(cand, result.route_states);
if (shortcut.a == -1) {
cand.exact_t = result.shortest_time;
cand.fixed_wall_count = fixed;
cand.valid = validate_candidate(cand);
if (!cand.valid) return false;
repaired = std::move(cand);
if ((int)repair_logs.size() < 6) {
repair_logs.push_back("repair_before_T=" + to_string(first_t) +
" added_fixed=" + to_string(fixed) +
" repair_after_T=" + to_string(repaired.exact_t) +
" success=1");
}
return true;
}
if (fixed == 33) {
if ((int)repair_logs.size() < 6) {
repair_logs.push_back("repair_before_T=" + to_string(first_t) +
" added_fixed=33 repair_after_T=" + to_string(result.shortest_time) +
" success=0");
}
return false;
}
if (!add_fixed_wall(cand, shortcut.a, shortcut.b)) return false;
if (!validate_candidate(cand)) return false;
}
return false;
}
vector<int> bfs_dist(int src) const {
vector<int> dist(N * N, -1);
queue<int> que;
dist[src] = 0;
que.push(src);
while (!que.empty()) {
int v = que.front();
que.pop();
for (int to : adj[v]) {
if (dist[to] != -1) continue;
dist[to] = dist[v] + 1;
que.push(to);
}
}
return dist;
}
Candidate make_fallback() const {
Candidate cand;
cand.valid = true;
for (int to : adj[goal_id()]) cand.doors.push_back(make_door(goal_id(), to, 19));
vector<int> ds = bfs_dist(start_id());
vector<int> dg = bfs_dist(goal_id());
int best_v = start_id();
int best_score = -1;
rep(v, N * N) {
if (!is_open_cell(v) || v == goal_id()) continue;
if (ds[v] < 0 || dg[v] < 0) continue;
int score = ds[v] + dg[v];
if (score > best_score) {
best_score = score;
best_v = v;
}
}
cand.switches.push_back({best_v, 9});
cand.exact_t = calc_T(cand);
cand.theoretical_t = cand.exact_t;
return cand;
}
bool validate_candidate(const Candidate& cand) const {
if ((int)cand.doors.size() > M) return false;
set<int> door_edges;
for (const Door& door : cand.doors) {
if (door.g <= 0 || door.g >= 2 * K) return false;
if (!is_open_cell(door.a) || !is_open_cell(door.b)) return false;
bool adjacent = false;
for (int to : adj[door.a]) if (to == door.b) adjacent = true;
if (!adjacent) return false;
int ek = edge_key(door.a, door.b);
if (door_edges.count(ek)) return false;
door_edges.insert(ek);
}
set<int> switch_cells;
for (const PlacedSwitch& sw : cand.switches) {
if (sw.s <= 0 || sw.s >= K) return false;
if (!is_open_cell(sw.v)) return false;
if (switch_cells.count(sw.v)) return false;
switch_cells.insert(sw.v);
}
return true;
}
void keep_seed_tree(vector<TreeState>& seeds, set<uint64_t>& seen_trees, TreeState state) const {
uint64_t h = tree_hash(state);
if (!seen_trees.insert(h).second) return;
seeds.push_back(std::move(state));
sort(seeds.begin(), seeds.end(), [](const TreeState& lhs, const TreeState& rhs) {
return lhs.score > rhs.score;
});
if ((int)seeds.size() > SA_SEED_COUNT) seeds.resize(SA_SEED_COUNT);
}
void keep_raw_candidate(vector<Candidate>& raw_pool,
set<uint64_t>& seen_raw,
Candidate cand) const {
keep_top_candidate(raw_pool, seen_raw, std::move(cand), RAW_POOL_LIMIT);
}
void anneal_from_seed(const TreeState& seed,
int chain_index,
double chain_start_ms,
double chain_end_ms,
mt19937& rng,
vector<Candidate>& raw_pool,
set<uint64_t>& seen_raw) {
TreeState current = seed;
TreeState best_in_chain = seed;
int chain_iterations = 0;
int chain_accepted = 0;
double start_temperature = max(50.0, abs(current.score) * 0.05);
const double end_temperature = 1.0;
uniform_real_distribution<double> dist01(0.0, 1.0);
while (elapsed_ms() < chain_end_ms) {
++sa_iteration_count;
++chain_iterations;
int add_eid = choose_add_edge(current, rng);
if (add_eid == -1) continue;
int u = all_edges[add_eid].u;
int v = all_edges[add_eid].v;
vector<int> path_edges = get_tree_path_edge_ids(current.tree_adj, u, v);
if (path_edges.empty()) continue;
int remove_eid = path_edges[(int)(rng() % path_edges.size())];
int previous_score = current.score;
remove_tree_edge(current, remove_eid);
add_tree_edge(current, add_eid);
Candidate next_candidate;
int next_score = -INF;
bool valid = evaluate_tree_fast(current.tree_adj, next_candidate, next_score);
if (valid) {
++sa_valid_neighbor_count;
keep_raw_candidate(raw_pool, seen_raw, next_candidate);
}
bool accept = false;
if (valid) {
int diff = next_score - previous_score;
double progress = (elapsed_ms() - chain_start_ms) / max(1.0, chain_end_ms - chain_start_ms);
progress = min(1.0, max(0.0, progress));
double temperature = start_temperature * pow(end_temperature / start_temperature, progress);
if (diff >= 0) {
accept = true;
} else {
accept = dist01(rng) < exp((double)diff / max(1e-9, temperature));
}
}
if (accept) {
current.score = next_score;
current.best_raw_candidate = next_candidate;
current.valid = true;
++sa_accepted_count;
++chain_accepted;
if (next_score < previous_score) ++sa_worse_accepted_count;
if (current.score > best_in_chain.score) {
best_in_chain = current;
++sa_best_update_count;
}
} else {
remove_tree_edge(current, add_eid);
add_tree_edge(current, remove_eid);
++sa_rejected_count;
}
}
keep_raw_candidate(raw_pool, seen_raw, best_in_chain.best_raw_candidate);
sa_final_best_score = max(sa_final_best_score, best_in_chain.score);
cerr << "chain_index=" << chain_index
<< " chain_initial_score=" << seed.score
<< " chain_final_current_score=" << current.score
<< " chain_best_score=" << best_in_chain.score
<< " chain_iteration_count=" << chain_iterations
<< " chain_accepted_count=" << chain_accepted
<< '\n';
}
Candidate choose_best_candidate() {
mt19937 rng((uint32_t)(board_hash ^ (board_hash >> 32)));
vector<Candidate> raw_candidate_pool;
set<uint64_t> seen_raw_candidates;
vector<TreeState> seed_trees;
set<uint64_t> seen_seed_trees;
while (elapsed_ms() < RANDOM_END_MS) {
TreeState state = generate_random_tree_state(rng);
++generated_tree_count;
++random_phase_tree_count;
if (!state.valid) continue;
Candidate best_raw;
int fast_score = -INF;
if (!evaluate_tree_fast(state.tree_adj, best_raw, fast_score)) continue;
state.best_raw_candidate = best_raw;
state.score = fast_score;
state.valid = true;
keep_seed_tree(seed_trees, seen_seed_trees, state);
keep_raw_candidate(raw_candidate_pool, seen_raw_candidates, std::move(best_raw));
}
int sa_seed_count = (int)seed_trees.size();
if (!seed_trees.empty()) sa_initial_best_score = seed_trees.front().score;
sa_final_best_score = sa_initial_best_score;
double anneal_start = elapsed_ms();
double remaining = max(0.0, ANNEAL_END_MS - anneal_start);
rep(i, (int)seed_trees.size()) {
if (elapsed_ms() >= ANNEAL_END_MS) break;
double chain_start = elapsed_ms();
double chain_span = remaining / max(1, (int)seed_trees.size());
double chain_end = min(ANNEAL_END_MS, chain_start + chain_span);
if (i + 1 == (int)seed_trees.size()) chain_end = ANNEAL_END_MS;
anneal_from_seed(seed_trees[i], i, chain_start, chain_end, rng, raw_candidate_pool, seen_raw_candidates);
}
Candidate best;
best.exact_t = -1;
sort(raw_candidate_pool.begin(), raw_candidate_pool.end(), [](const Candidate& lhs, const Candidate& rhs) {
if (lhs.selection_score != rhs.selection_score) return lhs.selection_score > rhs.selection_score;
return lhs.theoretical_t > rhs.theoretical_t;
});
int exact_limit = min<int>(EXACT_CANDIDATE_LIMIT, raw_candidate_pool.size());
rep(i, exact_limit) {
if (elapsed_ms() > EXACT_END_MS && best.exact_t >= 0) break;
++lazy_repair_attempt_count;
Candidate repaired;
bool ok = lazy_repair_candidate(raw_candidate_pool[i], repaired, EXACT_END_MS);
++exact_evaluated_count;
if (!ok) continue;
++lazy_repair_success_count;
if (repaired.exact_t > best.exact_t) best = std::move(repaired);
}
if (best.exact_t <= 0) best = make_fallback();
if (!validate_candidate(best)) best = make_fallback();
int main_path_length = max(0, (int)best.main_path.size() - 1);
int stem_length = max(0, min(best.index_a, best.index_b));
int connector_length = (best.index_a >= 0 && best.index_b >= 0) ? abs(best.index_a - best.index_b) : 0;
int c_length = max(0, (int)best.path_c.size() - 1);
double acceptance_rate = sa_iteration_count == 0 ? 0.0 : (double)sa_accepted_count / sa_iteration_count;
double worse_acceptance_rate = sa_iteration_count == 0 ? 0.0 : (double)sa_worse_accepted_count / sa_iteration_count;
cerr << "generated_tree_count=" << generated_tree_count
<< " generated_raw_candidate_count=" << generated_raw_candidate_count
<< " kept_raw_candidate_count=" << raw_candidate_pool.size()
<< " random_phase_tree_count=" << random_phase_tree_count
<< " sa_seed_count=" << sa_seed_count
<< " sa_iteration_count=" << sa_iteration_count
<< " sa_valid_neighbor_count=" << sa_valid_neighbor_count
<< " sa_accepted_count=" << sa_accepted_count
<< " sa_worse_accepted_count=" << sa_worse_accepted_count
<< " sa_rejected_count=" << sa_rejected_count
<< " sa_best_update_count=" << sa_best_update_count
<< " sa_initial_best_score=" << sa_initial_best_score
<< " sa_final_best_score=" << sa_final_best_score
<< " sa_acceptance_rate=" << acceptance_rate
<< " sa_worse_acceptance_rate=" << worse_acceptance_rate
<< " raw_candidate_pool_size=" << raw_candidate_pool.size()
<< " exact_attempt_count=" << lazy_repair_attempt_count
<< " lazy_repair_attempt_count=" << lazy_repair_attempt_count
<< " lazy_repair_success_count=" << lazy_repair_success_count
<< " exact_bfs_count=" << exact_bfs_count
<< " generated_side_path_count=" << generated_side_path_count
<< " examined_pair_count=" << examined_pair_count
<< " detailed_pair_count=" << detailed_pair_count
<< " valid_candidate_count=" << valid_candidate_count
<< " exact_evaluated_count=" << exact_evaluated_count
<< " best_main_path_length=" << main_path_length
<< " best_index_a=" << best.index_a
<< " best_index_b=" << best.index_b
<< " best_stem_length=" << stem_length
<< " best_connector_length=" << connector_length
<< " best_A_length=" << max(0, (int)best.path_a.size() - 1)
<< " best_B_length=" << max(0, (int)best.path_b.size() - 1)
<< " best_C_length=" << c_length
<< " best_full_isolation_wall_count=" << best.full_isolation_wall_count
<< " best_actual_fixed_wall_count=" << best.fixed_wall_count
<< " best_total_door_count=" << best.doors.size()
<< " best_theoretical_t=" << best.theoretical_t
<< " best_selection_score=" << best.selection_score
<< " best_exact_t=" << best.exact_t
<< " elapsed_ms=" << elapsed_ms()
<< '\n';
for (const string& log : repair_logs) cerr << log << '\n';
return best;
}
void print_door(const Door& door) const {
auto [ar, ac] = rc(door.a);
auto [br, bc] = rc(door.b);
if (ar == br) {
cout << 1 << ' ' << ar << ' ' << min(ac, bc) << ' ' << door.g << '\n';
} else {
cout << 0 << ' ' << min(ar, br) << ' ' << ac << ' ' << door.g << '\n';
}
}
void print_answer(const Candidate& cand) const {
cout << cand.doors.size() << '\n';
for (const Door& door : cand.doors) print_door(door);
cout << cand.switches.size() << '\n';
for (const PlacedSwitch& sw : cand.switches) {
auto [r, col] = rc(sw.v);
cout << r << ' ' << col << ' ' << sw.s << '\n';
}
}
void solve() {
start_time = chrono::steady_clock::now();
read_input();
build_graph();
Candidate answer = choose_best_candidate();
print_answer(answer);
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
Solver solver;
solver.solve();
return 0;
}
提出情報
ジャッジ結果
| セット名 |
test_ALL |
| 得点 / 配点 |
989253909 / 3000000000 |
| 結果 |
|
| セット名 |
テストケース |
| test_ALL |
test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt |
| ケース名 |
結果 |
実行時間 |
メモリ |
| test_0000.txt |
AC |
1905 ms |
11168 KiB |
| test_0001.txt |
AC |
1906 ms |
11116 KiB |
| test_0002.txt |
AC |
1908 ms |
11144 KiB |
| test_0003.txt |
AC |
1905 ms |
11124 KiB |
| test_0004.txt |
AC |
1906 ms |
11220 KiB |
| test_0005.txt |
AC |
1906 ms |
11392 KiB |
| test_0006.txt |
AC |
1905 ms |
11364 KiB |
| test_0007.txt |
AC |
1904 ms |
11104 KiB |
| test_0008.txt |
AC |
1906 ms |
11060 KiB |
| test_0009.txt |
AC |
1904 ms |
11240 KiB |
| test_0010.txt |
AC |
1904 ms |
11060 KiB |
| test_0011.txt |
AC |
1907 ms |
11252 KiB |
| test_0012.txt |
AC |
1905 ms |
11092 KiB |
| test_0013.txt |
AC |
1905 ms |
11040 KiB |
| test_0014.txt |
AC |
1907 ms |
11220 KiB |
| test_0015.txt |
AC |
1906 ms |
11404 KiB |
| test_0016.txt |
AC |
1904 ms |
11296 KiB |
| test_0017.txt |
AC |
1905 ms |
11032 KiB |
| test_0018.txt |
AC |
1907 ms |
11076 KiB |
| test_0019.txt |
AC |
1907 ms |
11192 KiB |
| test_0020.txt |
AC |
1905 ms |
11392 KiB |
| test_0021.txt |
AC |
1905 ms |
11292 KiB |
| test_0022.txt |
AC |
1906 ms |
11320 KiB |
| test_0023.txt |
AC |
1905 ms |
11380 KiB |
| test_0024.txt |
AC |
1906 ms |
11232 KiB |
| test_0025.txt |
AC |
1904 ms |
11284 KiB |
| test_0026.txt |
AC |
1905 ms |
11092 KiB |
| test_0027.txt |
AC |
1904 ms |
11052 KiB |
| test_0028.txt |
AC |
1907 ms |
11236 KiB |
| test_0029.txt |
AC |
1905 ms |
11164 KiB |
| test_0030.txt |
AC |
1905 ms |
10976 KiB |
| test_0031.txt |
AC |
1906 ms |
11136 KiB |
| test_0032.txt |
AC |
1906 ms |
11280 KiB |
| test_0033.txt |
AC |
1907 ms |
11192 KiB |
| test_0034.txt |
AC |
1906 ms |
11404 KiB |
| test_0035.txt |
AC |
1904 ms |
11268 KiB |
| test_0036.txt |
AC |
1905 ms |
11000 KiB |
| test_0037.txt |
AC |
1905 ms |
11208 KiB |
| test_0038.txt |
AC |
1906 ms |
11056 KiB |
| test_0039.txt |
AC |
1905 ms |
11208 KiB |
| test_0040.txt |
AC |
1905 ms |
11144 KiB |
| test_0041.txt |
AC |
1904 ms |
10972 KiB |
| test_0042.txt |
AC |
1906 ms |
11096 KiB |
| test_0043.txt |
AC |
1907 ms |
11200 KiB |
| test_0044.txt |
AC |
1906 ms |
11084 KiB |
| test_0045.txt |
AC |
1906 ms |
11268 KiB |
| test_0046.txt |
AC |
1906 ms |
11196 KiB |
| test_0047.txt |
AC |
1904 ms |
11304 KiB |
| test_0048.txt |
AC |
1905 ms |
11332 KiB |
| test_0049.txt |
AC |
1905 ms |
11436 KiB |
| test_0050.txt |
AC |
1907 ms |
11104 KiB |
| test_0051.txt |
AC |
1905 ms |
11260 KiB |
| test_0052.txt |
AC |
1904 ms |
11256 KiB |
| test_0053.txt |
AC |
1904 ms |
11108 KiB |
| test_0054.txt |
AC |
1904 ms |
11128 KiB |
| test_0055.txt |
AC |
1904 ms |
11152 KiB |
| test_0056.txt |
AC |
1906 ms |
11220 KiB |
| test_0057.txt |
AC |
1905 ms |
11208 KiB |
| test_0058.txt |
AC |
1905 ms |
11176 KiB |
| test_0059.txt |
AC |
1904 ms |
11112 KiB |
| test_0060.txt |
AC |
1906 ms |
11324 KiB |
| test_0061.txt |
AC |
1905 ms |
11200 KiB |
| test_0062.txt |
AC |
1905 ms |
11112 KiB |
| test_0063.txt |
AC |
1905 ms |
10980 KiB |
| test_0064.txt |
AC |
1905 ms |
11376 KiB |
| test_0065.txt |
AC |
1906 ms |
11112 KiB |
| test_0066.txt |
AC |
1907 ms |
11296 KiB |
| test_0067.txt |
AC |
1904 ms |
11104 KiB |
| test_0068.txt |
AC |
1904 ms |
11220 KiB |
| test_0069.txt |
AC |
1908 ms |
11276 KiB |
| test_0070.txt |
AC |
1904 ms |
11136 KiB |
| test_0071.txt |
AC |
1905 ms |
11172 KiB |
| test_0072.txt |
AC |
1905 ms |
11324 KiB |
| test_0073.txt |
AC |
1904 ms |
11240 KiB |
| test_0074.txt |
AC |
1904 ms |
11136 KiB |
| test_0075.txt |
AC |
1905 ms |
11100 KiB |
| test_0076.txt |
AC |
1905 ms |
11384 KiB |
| test_0077.txt |
AC |
1905 ms |
11144 KiB |
| test_0078.txt |
AC |
1905 ms |
11192 KiB |
| test_0079.txt |
AC |
1905 ms |
11036 KiB |
| test_0080.txt |
AC |
1907 ms |
11088 KiB |
| test_0081.txt |
AC |
1906 ms |
11268 KiB |
| test_0082.txt |
AC |
1906 ms |
11084 KiB |
| test_0083.txt |
AC |
1905 ms |
10980 KiB |
| test_0084.txt |
AC |
1907 ms |
11392 KiB |
| test_0085.txt |
AC |
1905 ms |
11100 KiB |
| test_0086.txt |
AC |
1906 ms |
11208 KiB |
| test_0087.txt |
AC |
1905 ms |
11252 KiB |
| test_0088.txt |
AC |
1905 ms |
11144 KiB |
| test_0089.txt |
AC |
1906 ms |
11272 KiB |
| test_0090.txt |
AC |
1905 ms |
11196 KiB |
| test_0091.txt |
AC |
1904 ms |
11316 KiB |
| test_0092.txt |
AC |
1905 ms |
11160 KiB |
| test_0093.txt |
AC |
1906 ms |
11156 KiB |
| test_0094.txt |
AC |
1905 ms |
11112 KiB |
| test_0095.txt |
AC |
1906 ms |
11352 KiB |
| test_0096.txt |
AC |
1908 ms |
11284 KiB |
| test_0097.txt |
AC |
1905 ms |
11196 KiB |
| test_0098.txt |
AC |
1907 ms |
11124 KiB |
| test_0099.txt |
AC |
1905 ms |
11364 KiB |
| test_0100.txt |
AC |
1905 ms |
11212 KiB |
| test_0101.txt |
AC |
1905 ms |
11072 KiB |
| test_0102.txt |
AC |
1906 ms |
11136 KiB |
| test_0103.txt |
AC |
1907 ms |
11168 KiB |
| test_0104.txt |
AC |
1906 ms |
11172 KiB |
| test_0105.txt |
AC |
1905 ms |
11336 KiB |
| test_0106.txt |
AC |
1905 ms |
11324 KiB |
| test_0107.txt |
AC |
1906 ms |
11164 KiB |
| test_0108.txt |
AC |
1905 ms |
11144 KiB |
| test_0109.txt |
AC |
1906 ms |
11120 KiB |
| test_0110.txt |
AC |
1906 ms |
11212 KiB |
| test_0111.txt |
AC |
1905 ms |
11048 KiB |
| test_0112.txt |
AC |
1905 ms |
11048 KiB |
| test_0113.txt |
AC |
1906 ms |
11340 KiB |
| test_0114.txt |
AC |
1904 ms |
11288 KiB |
| test_0115.txt |
AC |
1907 ms |
11392 KiB |
| test_0116.txt |
AC |
1906 ms |
11220 KiB |
| test_0117.txt |
AC |
1905 ms |
11172 KiB |
| test_0118.txt |
AC |
1905 ms |
11076 KiB |
| test_0119.txt |
AC |
1906 ms |
11240 KiB |
| test_0120.txt |
AC |
1906 ms |
11200 KiB |
| test_0121.txt |
AC |
1904 ms |
11328 KiB |
| test_0122.txt |
AC |
1905 ms |
11184 KiB |
| test_0123.txt |
AC |
1907 ms |
11180 KiB |
| test_0124.txt |
AC |
1904 ms |
11252 KiB |
| test_0125.txt |
AC |
1905 ms |
11284 KiB |
| test_0126.txt |
AC |
1904 ms |
11292 KiB |
| test_0127.txt |
AC |
1906 ms |
11300 KiB |
| test_0128.txt |
AC |
1904 ms |
11448 KiB |
| test_0129.txt |
AC |
1905 ms |
11268 KiB |
| test_0130.txt |
AC |
1904 ms |
11280 KiB |
| test_0131.txt |
AC |
1905 ms |
11200 KiB |
| test_0132.txt |
AC |
1905 ms |
11356 KiB |
| test_0133.txt |
AC |
1905 ms |
11240 KiB |
| test_0134.txt |
AC |
1905 ms |
11004 KiB |
| test_0135.txt |
AC |
1905 ms |
11088 KiB |
| test_0136.txt |
AC |
1907 ms |
11240 KiB |
| test_0137.txt |
AC |
1904 ms |
11288 KiB |
| test_0138.txt |
AC |
1907 ms |
11376 KiB |
| test_0139.txt |
AC |
1907 ms |
11236 KiB |
| test_0140.txt |
AC |
1905 ms |
11272 KiB |
| test_0141.txt |
AC |
1906 ms |
11096 KiB |
| test_0142.txt |
AC |
1905 ms |
11260 KiB |
| test_0143.txt |
AC |
1906 ms |
11240 KiB |
| test_0144.txt |
AC |
1904 ms |
11344 KiB |
| test_0145.txt |
AC |
1905 ms |
11108 KiB |
| test_0146.txt |
AC |
1904 ms |
11272 KiB |
| test_0147.txt |
AC |
1904 ms |
11316 KiB |
| test_0148.txt |
AC |
1905 ms |
11320 KiB |
| test_0149.txt |
AC |
1907 ms |
11492 KiB |