結果
問題 |
No.5022 XOR Printer
|
ユーザー |
|
提出日時 | 2025-07-26 15:33:52 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 1,805 ms / 2,000 ms |
コード長 | 6,633 bytes |
コンパイル時間 | 3,779 ms |
コンパイル使用メモリ | 306,496 KB |
実行使用メモリ | 7,720 KB |
スコア | 4,409,129,460 |
最終ジャッジ日時 | 2025-07-26 15:35:31 |
合計ジャッジ時間 | 98,187 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
#include <bits/stdc++.h> using namespace std; #pragma GCC optimize("O3") #define all(x) (x).begin(),(x).end() typedef long long ll; const long long INF = 1LL << 60; // 十分大きな値 (ここでは 2^60 とする) #include <algorithm> #include <cctype> #include <cstddef> #include <iostream> #include <iterator> #include <string_view> #include <type_traits> template<class T> void chmin(T& a, T b) { if (a > b) { a = b; } } template<class T> void chmax(T& a, T b) { if (a < b) { a = b; } } #ifdef LOCAL # include <debug_print.hpp> # define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__) #else # define debug(...) (static_cast<void>(0)) #endif int N, T; vector<vector<int>> A; int x = 0, y = 0, s = 0; vector<string> command_list = {"U", "D", "L", "R", "W", "C"}; // 移動可能かどうかを判定 bool can_move(int x, int y, const string& command) { if (command == "U") { return x > 0; } else if (command == "D") { return x < N - 1; } else if (command == "L") { return y > 0; } else if (command == "R") { return y < N - 1; } return true; } // コマンドを実行 void process_command(vector<vector<int>>& board, int& x, int& y, int& s, const string& command) { if (command == "U") { x = x - 1; } else if (command == "D") { x = x + 1; } else if (command == "L") { y = y - 1; } else if (command == "R") { y = y + 1; } else if (command == "W") { board[x][y] ^= s; } else if (command == "C") { s ^= board[x][y]; } } // スコアを計算 int calc_score(const vector<vector<int>>& board) { int score = 0; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { score += board[i][j]; } } return score; } // 盤面の初期値を保持(焼きなまし時のリセット用) vector<vector<int>> initial_board; // 時間計測用 inline long long now() { return chrono::duration_cast<chrono::milliseconds>( chrono::steady_clock::now().time_since_epoch()) .count(); } // 与えられた手列をシミュレートし,スコアを返す。 // 無効な手列なら false を返す。 bool simulate(const vector<string>& seq, long long& score_out) { vector<vector<int>> board = initial_board; // コピー int tx = 0, ty = 0, ts = 0; for (const string& cmd : seq) { if ((cmd == "U" || cmd == "D" || cmd == "L" || cmd == "R") && !can_move(tx, ty, cmd)) { return false; // 壁に衝突 } process_command(board, tx, ty, ts, cmd); } score_out = calc_score(board); return true; } // Greedy で初期手列を構築 vector<string> build_greedy_sequence(int T) { vector<string> seq; seq.reserve(T); vector<vector<int>> board = initial_board; int cx = 0, cy = 0, cs = 0; random_device rd; mt19937 rng(rd()); for (int step = 0; step < T; ++step) { long long best_score = LLONG_MIN; string best_cmd = "W"; // 現在の盤面得点 long long base_score = calc_score(board); // 試せるコマンドを列挙 for (const string& cmd : command_list) { if ((cmd == "U" || cmd == "D" || cmd == "L" || cmd == "R") && !can_move(cx, cy, cmd)) continue; // 状態をコピーして 1 手だけ適用 int nx = cx, ny = cy, ns = cs; vector<vector<int>> tmp_board = board; process_command(tmp_board, nx, ny, ns, cmd); long long sc = calc_score(tmp_board); if (sc > best_score) { best_score = sc; best_cmd = cmd; } } // すべての cmd が同点(動かすだけ)ならランダムで選ぶ if (best_score <= base_score) { // ランダムで動ける方向または C を選択 vector<string> cand; for (const string& cmd : command_list) { if ((cmd == "U" || cmd == "D" || cmd == "L" || cmd == "R")) { if (can_move(cx, cy, cmd)) cand.push_back(cmd); } else { cand.push_back(cmd); // W or C } } uniform_int_distribution<int> uni(0, (int)cand.size() - 1); best_cmd = cand[uni(rng)]; } // best_cmd を実際に適用 process_command(board, cx, cy, cs, best_cmd); seq.push_back(best_cmd); } return seq; } // 焼きなましで手列を改善 vector<string> simulated_annealing(vector<string> seq, long long best_score, long long time_limit_ms = 1800) { const long long start_time = now(); const double T0 = 2000.0; const double T_end = 1e-3; random_device rd; mt19937 rng(rd()); uniform_int_distribution<int> cmd_dist(0, (int)command_list.size() - 1); vector<string> best_seq = seq; long long iter = 0; while (now() - start_time < time_limit_ms) { ++iter; double progress = (double)(now() - start_time) / (double)time_limit_ms; double temperature = pow(T_end / T0, progress) * T0; // ランダム区間を書き換え (長さ 1~10) uniform_int_distribution<int> pos_dist(0, T - 1); int l = pos_dist(rng); int len = min(T - l, (int)(pos_dist(rng) % 10 + 1)); vector<string> new_seq = seq; for (int i = l; i < l + len; ++i) { new_seq[i] = command_list[cmd_dist(rng)]; } long long new_score; if (!simulate(new_seq, new_score)) continue; // 無効手列 long long delta = new_score - best_score; if (delta > 0 || exp(delta / temperature) > (double)rng() / rng.max()) { // 受理 seq.swap(new_seq); best_score = new_score; if (best_score > calc_score(initial_board)) { best_seq = seq; } } } return best_seq; } int main() { // 入力 cin >> N >> T; A.resize(N, vector<int>(N)); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { cin >> A[i][j]; } } // 初期盤面を保存 initial_board = A; // Greedy で初期手列を生成 vector<string> seq = build_greedy_sequence(T); long long best_score; simulate(seq, best_score); // 焼きなましで改善 seq = simulated_annealing(seq, best_score); // 出力 for (const string& cmd : seq) { cout << cmd << '\n'; } return 0; }