結果
| 問題 |
No.5022 XOR Printer
|
| コンテスト | |
| ユーザー |
ぴぃいいいい
|
| 提出日時 | 2025-07-30 00:17:51 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 3 ms / 2,000 ms |
| コード長 | 9,890 bytes |
| コンパイル時間 | 1,201 ms |
| コンパイル使用メモリ | 109,000 KB |
| 実行使用メモリ | 7,716 KB |
| スコア | 5,209,531,981 |
| 最終ジャッジ日時 | 2025-07-30 00:17:55 |
| 合計ジャッジ時間 | 3,682 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
ソースコード
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <utility>
#include <vector>
#include <algorithm>
#include <climits>
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;
// 操作タイプ
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);
}
};
// グローバル変数
int s; // 現在のスコア状態
int t; // 残り操作回数
int n; // 入力パラメータ
Position cur_pos; // 現在位置
int a[GRID_SZ][GRID_SZ]; // グリッドの値
Position route[TOTAL_CELLS]; // 事前計算されたルート
// 関数宣言
void input();
void move_to(const Position& target);
void exec_cmd(Command cmd);
Position find_nearest_bit_target(int bit);
vector<Position> solve_tsp(const vector<Position>& targets);
// 操作を出力し、操作回数を管理する関数
void exec_cmd(Command cmd) {
putchar(static_cast<char>(cmd));
putchar('\n');
// 残り操作が緊急閾値になったら特別な終了処理
if (--t == EMERG_THRESH) {
Position emerg_pos1(0, 5);
Position emerg_pos2(0, 4);
move_to(emerg_pos1);
exec_cmd(COLLECT);
s ^= a[emerg_pos1.x][emerg_pos1.y];
move_to(emerg_pos2);
exec_cmd(COLLECT);
s ^= a[emerg_pos2.x][emerg_pos2.y];
move_to(emerg_pos1);
exec_cmd(WRITE);
a[emerg_pos1.x][emerg_pos1.y] ^= s;
exit(0);
}
}
// 指定座標に移動する関数
void move_to(const Position& target) {
while (cur_pos.x < target.x) {
++cur_pos.x;
exec_cmd(DOWN);
}
while (cur_pos.x > target.x) {
--cur_pos.x;
exec_cmd(UP);
}
while (cur_pos.y < target.y) {
++cur_pos.y;
exec_cmd(RIGHT);
}
while (cur_pos.y > target.y) {
--cur_pos.y;
exec_cmd(LEFT);
}
}
// インデックスから座標を計算する関数
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個の座標計算(蛇行パターン)
// x軸:UP/DOWN方向、y軸:RIGHT/LEFT方向
int x = q / SNAKE_W;
int y = (q / SNAKE_W % 2) ? (q % SNAKE_W) : (SNAKE_W - 1 - q % SNAKE_W);
return Position(x, y);
}
}
// ステップ1改善: 条件を満たす座標の中で現在地から最も近い座標を選択
Position find_nearest_bit_target(int bit) {
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;
}
// ルートの総距離を計算
int calculate_total_distance(const vector<Position>& route) {
if (route.size() <= 1) return 0;
int total = cur_pos.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) {
bool improved = false;
int n = route.size();
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 2; j < n; ++j) { // j = i + 2 to avoid adjacent edges
// 元の距離
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解決(貪欲法 + 2-opt局所探索)
vector<Position> solve_tsp(const vector<Position>& targets) {
if (targets.empty()) return vector<Position>();
if (targets.size() == 1) return targets;
vector<Position> result;
vector<bool> visited(targets.size(), false);
// Step 1: 貪欲法で初期解を生成
// 現在地から最も近い点を開始点とする
int current_idx = 0;
int min_distance = INT_MAX;
for (size_t i = 0; i < targets.size(); ++i) {
int distance = cur_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) {
int next_idx = -1;
min_distance = INT_MAX;
for (size_t i = 0; i < targets.size(); ++i) {
if (!visited[i]) {
int distance = targets[current_idx].distance_to(targets[i]);
if (distance < min_distance) {
min_distance = distance;
next_idx = i;
}
}
}
if (next_idx != -1) {
visited[next_idx] = true;
result.push_back(targets[next_idx]);
current_idx = next_idx;
}
}
// Step 2: 2-opt局所探索で改善(小さなリストのみ、計算時間を制限)
int max_iterations = 10000; // 反復回数制限で時間を制御
for (int iter = 0; iter < max_iterations; ++iter) {
if (!two_opt_improve(result)) {
break; // これ以上改善できない場合終了
}
}
return result;
}
// 入力を受け取る関数
void input() {
// 入力読み込み
cin >> n >> t;
// 入力はa[行][列]で読み込み、a[x][y]として格納
// x軸:UP/DOWN方向(行)、y軸:RIGHT/LEFT方向(列)
for (int i = 0; i < GRID_SZ; ++i) {
for (int j = 0; j < GRID_SZ; ++j) {
cin >> a[i][j]; // a[x][y] = a[行][列]
}
}
}
int main() {
input();
// ルートの事前計算
for (int q = 0; q < TOTAL_CELLS; ++q) {
route[q] = calc_pos(q);
}
// ビット位置ごとの処理(上位ビットから)
for (int b = BITS_CNT - 1; b >= 0; --b) {
fprintf(stderr, "b=%d\n", b);
// ステップ1改善: ビットbを立てるための値を探す(最近傍選択)
Position target_pos = find_nearest_bit_target(b);
if (target_pos.x != -1) { // 有効な座標が見つかった場合
move_to(target_pos);
exec_cmd(COLLECT);
s ^= a[target_pos.x][target_pos.y];
}
// ビットbが立っていない場合はスキップ
if ((s >> b) != 1) {
continue;
}
// ステップ3改善: ビットbが0の箇所を列挙してTSPで最適化
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);
}
}
}
// TSPで最適な巡回順序を決定(タイムアウト対策として、大きなリストは制限)
if (write_targets.size() > 0 && write_targets.size() <= 50) {
vector<Position> optimal_order = solve_tsp(write_targets);
// 最適順序でWRITE操作を実行
for (const Position& pos : optimal_order) {
if (t <= EMERG_THRESH) break; // 緊急閾値チェック
move_to(pos);
exec_cmd(WRITE);
a[pos.x][pos.y] ^= s;
}
} else {
// フォールバック: 元のアルゴリズムを使用
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)) {
if (t <= EMERG_THRESH) break;
move_to(pos);
exec_cmd(WRITE);
a[pos.x][pos.y] ^= s;
}
}
}
}
// 特定位置での追加処理
if (b < BITS_CNT - 1) {
int idx = TOTAL_CELLS - (BITS_CNT - 1 - b);
Position pos = route[idx];
move_to(pos);
exec_cmd(WRITE);
a[pos.x][pos.y] ^= s;
exec_cmd(COLLECT);
s ^= a[pos.x][pos.y];
}
}
return 0;
}
ぴぃいいいい