結果
問題 |
No.5022 XOR Printer
|
ユーザー |
![]() |
提出日時 | 2025-07-30 01:03:57 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 1,953 ms / 2,000 ms |
コード長 | 12,287 bytes |
コンパイル時間 | 2,617 ms |
コンパイル使用メモリ | 211,008 KB |
実行使用メモリ | 7,716 KB |
スコア | 5,203,882,686 |
最終ジャッジ日時 | 2025-07-30 01:05:42 |
合計ジャッジ時間 | 104,685 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
#include <iostream> #include <cstdio> #include <cstdlib> #include <utility> #include <vector> #include <algorithm> #include <climits> #include <chrono> #include <random> using namespace std; // 定数定義 const int GRID_SZ = 10; const int TOTAL_CELLS = 100; const int HALF_CELLS = 50; const int BITS_CNT = 20; const int EMERG_THRESH = 20; const int GRID_MAX_IDX = 9; const int SNAKE_W = 5; const double TIME_LIMIT = 1.95; // 実行時間制限(秒) // 操作タイプ enum Command { COLLECT = 'C', // 値を取得 WRITE = 'W', // 値を書き込み UP = 'U', // 上移動 DOWN = 'D', // 下移動 LEFT = 'L', // 左移動 RIGHT = 'R' // 右移動 }; // 座標構造体 struct Position { int x, y; Position(int x = 0, int y = 0) : x(x), y(y) {} // マンハッタン距離を計算 int distance_to(const Position& other) const { return abs(x - other.x) + abs(y - other.y); } }; // ソリューション結果を格納する構造体 struct SolutionResult { vector<Command> operations; long long final_score; int operations_count; SolutionResult() : final_score(0), operations_count(0) {} }; // グローバル変数 int n, t_limit; int original_a[GRID_SZ][GRID_SZ]; // 元のグリッド値(バックアップ用) Position route[TOTAL_CELLS]; // 事前計算されたルート mt19937 rng; // 乱数生成器 chrono::high_resolution_clock::time_point start_time; // 関数宣言 void input(); Position calc_pos(int q); SolutionResult solve_once(int seed); long long calculate_final_score(const int grid[GRID_SZ][GRID_SZ]); vector<Position> solve_tsp_randomized(const vector<Position>& targets, const Position& current_pos, mt19937& gen); bool two_opt_improve(vector<Position>& route, mt19937& gen); int calculate_total_distance(const vector<Position>& route, const Position& start); // 時間チェック関数 bool is_time_limit_reached() { auto current_time = chrono::high_resolution_clock::now(); auto elapsed = chrono::duration<double>(current_time - start_time).count(); return elapsed >= TIME_LIMIT; } // 最終スコアを計算 long long calculate_final_score(const int grid[GRID_SZ][GRID_SZ]) { long long score = 0; for (int i = 0; i < GRID_SZ; ++i) { for (int j = 0; j < GRID_SZ; ++j) { score += grid[i][j]; } } return score; } // インデックスから座標を計算する関数 Position calc_pos(int q) { if (q >= HALF_CELLS) { // 後半50個は前半の鏡像 Position pos = calc_pos(q - HALF_CELLS); return Position(GRID_MAX_IDX - pos.x, GRID_MAX_IDX - pos.y); } else { // 前半50個の座標計算(蛇行パターン) int x = q / SNAKE_W; int y = (q / SNAKE_W % 2) ? (q % SNAKE_W) : (SNAKE_W - 1 - q % SNAKE_W); return Position(x, y); } } // ルートの総距離を計算 int calculate_total_distance(const vector<Position>& route, const Position& start) { if (route.size() <= 1) return 0; int total = start.distance_to(route[0]); // スタート地点から最初の点まで for (size_t i = 0; i < route.size() - 1; ++i) { total += route[i].distance_to(route[i + 1]); } return total; } // 2-opt改善を実行(ランダムな探索順序) bool two_opt_improve(vector<Position>& route, mt19937& gen) { bool improved = false; int n = route.size(); // i,jのペアをランダムな順序で探索 vector<pair<int, int>> pairs; for (int i = 0; i < n - 1; ++i) { for (int j = i + 2; j < n; ++j) { pairs.push_back({i, j}); } } // ペアをランダムにシャッフル shuffle(pairs.begin(), pairs.end(), gen); for (const auto& p : pairs) { int i = p.first; int j = p.second; // 元の距離 int old_dist = route[i].distance_to(route[i + 1]) + route[j].distance_to(route[(j + 1) % n]); // 2-opt交換後の距離 int new_dist = route[i].distance_to(route[j]) + route[i + 1].distance_to(route[(j + 1) % n]); if (new_dist < old_dist) { // 区間 [i+1, j] を逆順にする reverse(route.begin() + i + 1, route.begin() + j + 1); improved = true; } } return improved; } // ランダム性を持たせたTSP解決 vector<Position> solve_tsp_randomized(const vector<Position>& targets, const Position& current_pos, mt19937& gen) { if (targets.empty()) return vector<Position>(); if (targets.size() == 1) return targets; vector<Position> result; vector<bool> visited(targets.size(), false); // 現在地から最も近い点を開始点とする int current_idx = 0; int min_distance = INT_MAX; for (size_t i = 0; i < targets.size(); ++i) { int distance = current_pos.distance_to(targets[i]); if (distance < min_distance) { min_distance = distance; current_idx = i; } } visited[current_idx] = true; result.push_back(targets[current_idx]); // 貪欲法でTSPを近似的に解く for (size_t count = 1; count < targets.size(); ++count) { vector<pair<int, int>> candidates; // {distance, index} for (size_t i = 0; i < targets.size(); ++i) { if (!visited[i]) { int distance = targets[current_idx].distance_to(targets[i]); candidates.push_back({distance, i}); } } if (candidates.empty()) break; // 距離でソートし、最短距離を選択 sort(candidates.begin(), candidates.end()); int next_idx = candidates[0].second; visited[next_idx] = true; result.push_back(targets[next_idx]); current_idx = next_idx; } // 2-opt局所探索で改善 int max_iterations = 1000; for (int iter = 0; iter < max_iterations; ++iter) { if (!two_opt_improve(result, gen)) { break; } } return result; } // 一度のソリューション実行 SolutionResult solve_once(int seed) { SolutionResult result; // 乱数生成器を初期化 mt19937 local_rng(seed); // グリッドをコピー int a[GRID_SZ][GRID_SZ]; for (int i = 0; i < GRID_SZ; ++i) { for (int j = 0; j < GRID_SZ; ++j) { a[i][j] = original_a[i][j]; } } int s = 0; // 現在のスコア状態 int t = t_limit; // 残り操作回数 Position cur_pos(0, 0); // 現在位置 // ビット順序は上位ビットから固定順序で処理 auto move_to = [&](const Position& target) { while (cur_pos.x < target.x) { ++cur_pos.x; result.operations.push_back(DOWN); if (++result.operations_count >= t_limit) return; } while (cur_pos.x > target.x) { --cur_pos.x; result.operations.push_back(UP); if (++result.operations_count >= t_limit) return; } while (cur_pos.y < target.y) { ++cur_pos.y; result.operations.push_back(RIGHT); if (++result.operations_count >= t_limit) return; } while (cur_pos.y > target.y) { --cur_pos.y; result.operations.push_back(LEFT); if (++result.operations_count >= t_limit) return; } }; auto find_nearest_bit_target = [&](int bit) -> Position { Position best_pos(-1, -1); int min_distance = INT_MAX; for (int q = 0; q < TOTAL_CELLS; ++q) { Position pos = route[q]; if ((s ^ a[pos.x][pos.y]) >> bit == 1) { int distance = cur_pos.distance_to(pos); if (distance < min_distance) { min_distance = distance; best_pos = pos; } } } return best_pos; }; // ビット位置ごとの処理(上位ビットから) for (int b = BITS_CNT - 1; b >= 0; --b) { if (result.operations_count >= t_limit - EMERG_THRESH) break; // ステップ1: ビットbを立てるための値を探す Position target_pos = find_nearest_bit_target(b); if (target_pos.x != -1) { move_to(target_pos); if (result.operations_count >= t_limit) break; result.operations.push_back(COLLECT); ++result.operations_count; s ^= a[target_pos.x][target_pos.y]; } // ビットbが立っていない場合はスキップ if ((s >> b) != 1) { continue; } // ステップ2: ビットbが0の箇所を列挙 vector<Position> write_targets; for (int q = 0; q < TOTAL_CELLS; ++q) { Position pos = route[q]; if (pos.x >= 0 && pos.x < GRID_SZ && pos.y >= 0 && pos.y < GRID_SZ) { if (!(a[pos.x][pos.y] >> b & 1)) { write_targets.push_back(pos); } } } // ステップ3: TSPで最適な巡回順序を決定 if (write_targets.size() > 0) { vector<Position> optimal_order = solve_tsp_randomized(write_targets, cur_pos, local_rng); // 最適順序でWRITE操作を実行 for (const Position& pos : optimal_order) { if (result.operations_count >= t_limit - EMERG_THRESH) break; move_to(pos); if (result.operations_count >= t_limit) break; result.operations.push_back(WRITE); ++result.operations_count; a[pos.x][pos.y] ^= s; } } // 特定位置での追加処理 if (b < BITS_CNT - 1 && result.operations_count < t_limit - EMERG_THRESH) { int idx = TOTAL_CELLS - (BITS_CNT - 1 - b); Position pos = route[idx]; move_to(pos); if (result.operations_count < t_limit) { result.operations.push_back(WRITE); ++result.operations_count; a[pos.x][pos.y] ^= s; result.operations.push_back(COLLECT); ++result.operations_count; s ^= a[pos.x][pos.y]; } } } result.final_score = calculate_final_score(a); return result; } // 入力を受け取る関数 void input() { cin >> n >> t_limit; for (int i = 0; i < GRID_SZ; ++i) { for (int j = 0; j < GRID_SZ; ++j) { cin >> original_a[i][j]; } } } int main() { start_time = chrono::high_resolution_clock::now(); input(); // ルートの事前計算 for (int q = 0; q < TOTAL_CELLS; ++q) { route[q] = calc_pos(q); } // 乱数生成器を初期化 random_device rd; rng.seed(rd()); SolutionResult best_solution; int iteration = 0; // 時間制限まで複数回実行 while (!is_time_limit_reached()) { int seed = rng(); SolutionResult current_solution = solve_once(seed); if (current_solution.final_score > best_solution.final_score) { best_solution = current_solution; fprintf(stderr, "Iteration %d: New best score = %lld (operations: %d)\n", iteration, best_solution.final_score, best_solution.operations_count); } ++iteration; // 最小でも1回は実行する if (iteration == 1 && !is_time_limit_reached()) { continue; } } // 最良解を出力 for (Command cmd : best_solution.operations) { putchar(static_cast<char>(cmd)); putchar('\n'); } fprintf(stderr, "Total iterations: %d\n", iteration); fprintf(stderr, "Best score: %lld\n", best_solution.final_score); fprintf(stderr, "Operations used: %d/%d\n", best_solution.operations_count, t_limit); return 0; }