結果
| 問題 |
No.5022 XOR Printer
|
| コンテスト | |
| ユーザー |
ぴぃいいいい
|
| 提出日時 | 2025-07-28 08:00:45 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,804 ms / 2,000 ms |
| コード長 | 9,815 bytes |
| コンパイル時間 | 2,778 ms |
| コンパイル使用メモリ | 214,356 KB |
| 実行使用メモリ | 7,716 KB |
| スコア | 4,456,616,252 |
| 最終ジャッジ日時 | 2025-07-28 08:02:24 |
| 合計ジャッジ時間 | 97,283 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
ソースコード
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <random>
#include <chrono>
#include <climits>
using namespace std;
int N, T;
vector<vector<int>> A;
vector<pair<int, int>> circuit; // 10x10のマス巡回回路
mt19937 rng;
// 各マスの各周回での行動を表す構造体
struct CellAction {
bool copy;
bool write;
};
// 解を表す構造体(複数周回分の行動を記録)
struct Solution {
vector<vector<CellAction>> actions; // actions[round][cell_index]
int max_rounds; // 最大周回数
long long score;
Solution(int rounds = 10) : max_rounds(rounds) {
score = 0;
actions.resize(max_rounds);
for (int r = 0; r < max_rounds; r++) {
actions[r].resize(N * N);
}
}
};
void input() {
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];
}
}
}
// 10x10グリッドの巡回回路を生成(効率的なルート)
void generateCircuit() {
circuit.clear();
// 蛇行パターンで全マスを1回ずつ通る
for (int i = 0; i < N; i++) {
if (i % 2 == 0) {
// 偶数行:左から右へ
for (int j = 0; j < N; j++) {
circuit.push_back({i, j});
}
} else {
// 奇数行:右から左へ
for (int j = N - 1; j >= 0; j--) {
circuit.push_back({i, j});
}
}
}
}
// 移動コストを計算
int calculateMoveCost() {
int moves = 0;
for (int i = 1; i < circuit.size(); i++) {
moves += abs(circuit[i].first - circuit[i-1].first) +
abs(circuit[i].second - circuit[i-1].second);
}
return moves;
}
// 解のスコアを計算(シミュレーション)
long long calculateScore(const Solution& sol) {
vector<vector<int>> grid = A;
int s = 0;
int operations = 0;
int currentR = 0, currentC = 0;
// 複数周回のシミュレーション
for (int round = 0; round < sol.max_rounds && operations < T; round++) {
for (int cell_idx = 0; cell_idx < circuit.size() && operations < T; cell_idx++) {
int targetR = circuit[cell_idx].first;
int targetC = circuit[cell_idx].second;
// 目標位置への移動
while ((currentR != targetR || currentC != targetC) && operations < T) {
if (currentR < targetR) {
operations++;
currentR++;
} else if (currentR > targetR) {
operations++;
currentR--;
} else if (currentC < targetC) {
operations++;
currentC++;
} else if (currentC > targetC) {
operations++;
currentC--;
} else {
break;
}
}
if (operations >= T) break;
// このマスでのコピー操作
if (sol.actions[round][cell_idx].copy && operations < T) {
operations++;
s ^= grid[currentR][currentC];
}
// このマスでの書き込み操作
if (sol.actions[round][cell_idx].write && operations < T) {
operations++;
grid[currentR][currentC] ^= s;
}
}
}
// 最終スコア計算
long long totalScore = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
totalScore += grid[i][j];
}
}
return totalScore;
}
// 初期解を生成
Solution generateRandomSolution() {
Solution sol(8); // 最大8周回
uniform_real_distribution<double> dist(0.0, 1.0);
for (int round = 0; round < sol.max_rounds; round++) {
for (int cell = 0; cell < N * N; cell++) {
// 周回が進むにつれて操作確率を調整
double copy_prob = 0.5 / (1.0 + round * 0.1); // 周回が進むと確率減少
double write_prob = 0.4 / (1.0 + round * 0.1);
sol.actions[round][cell].copy = (dist(rng) < copy_prob);
sol.actions[round][cell].write = (dist(rng) < write_prob);
}
}
sol.score = calculateScore(sol);
return sol;
}
// 近傍解を生成(特定の周回・セルの行動を変更)
Solution generateNeighbor(const Solution& current) {
Solution neighbor = current;
uniform_int_distribution<int> round_dist(0, current.max_rounds - 1);
uniform_int_distribution<int> cell_dist(0, N * N - 1);
uniform_real_distribution<double> action_dist(0.0, 1.0);
// 変更する周回数を決定(1-3周回を変更)
int rounds_to_change = uniform_int_distribution<int>(1, 3)(rng);
for (int i = 0; i < rounds_to_change; i++) {
int round = round_dist(rng);
int cell = cell_dist(rng);
// コピーまたは書き込み操作を反転
if (action_dist(rng) < 0.5) {
neighbor.actions[round][cell].copy = !neighbor.actions[round][cell].copy;
} else {
neighbor.actions[round][cell].write = !neighbor.actions[round][cell].write;
}
}
neighbor.score = calculateScore(neighbor);
return neighbor;
}
// 改良された焼きなまし法
Solution simulatedAnnealing() {
const double TIME_LIMIT = 1.8;
const double START_TEMP = 100000.0;
const double END_TEMP = 0.1;
auto start_time = chrono::high_resolution_clock::now();
Solution current = generateRandomSolution();
Solution best = current;
uniform_real_distribution<double> prob_dist(0.0, 1.0);
int iter = 0;
int accepted = 0;
int total_attempts = 0;
int improvements = 0;
while (true) {
auto current_time = chrono::high_resolution_clock::now();
double elapsed = chrono::duration<double>(current_time - start_time).count();
if (elapsed >= TIME_LIMIT) break;
double progress = elapsed / TIME_LIMIT;
// 温度スケジューリング
double temp = START_TEMP * pow(END_TEMP / START_TEMP, progress);
Solution neighbor = generateNeighbor(current);
total_attempts++;
double delta = neighbor.score - current.score;
bool accept = false;
if (delta > 0) {
accept = true;
improvements++;
} else if (temp > END_TEMP) {
double acceptance_prob = exp(delta / temp);
accept = (acceptance_prob > prob_dist(rng));
}
if (accept) {
current = neighbor;
accepted++;
if (current.score > best.score) {
best = current;
}
}
// デバッグ出力
if (iter % 5000 == 0) {
double acceptance_rate = (double)accepted / max(1, total_attempts);
cerr << "Time: " << elapsed << "s, Temp: " << temp
<< ", Acceptance: " << acceptance_rate
<< ", Score: " << current.score << ", Best: " << best.score << endl;
}
iter++;
}
cerr << "Final: " << iter << " iterations, Best score: " << best.score << endl;
return best;
}
// 操作列を生成
vector<char> generateOperations(const Solution& sol) {
vector<char> operations;
int currentR = 0, currentC = 0;
// 複数周回の操作を生成
for (int round = 0; round < sol.max_rounds && operations.size() < T; round++) {
for (int cell_idx = 0; cell_idx < circuit.size() && operations.size() < T; cell_idx++) {
int targetR = circuit[cell_idx].first;
int targetC = circuit[cell_idx].second;
// 移動操作
while ((currentR != targetR || currentC != targetC) && operations.size() < T) {
if (currentR < targetR) {
operations.push_back('D');
currentR++;
} else if (currentR > targetR) {
operations.push_back('U');
currentR--;
} else if (currentC < targetC) {
operations.push_back('R');
currentC++;
} else if (currentC > targetC) {
operations.push_back('L');
currentC--;
} else {
break;
}
}
if (operations.size() >= T) break;
// コピー操作
if (sol.actions[round][cell_idx].copy && operations.size() < T) {
operations.push_back('C');
}
// 書き込み操作
if (sol.actions[round][cell_idx].write && operations.size() < T) {
operations.push_back('W');
}
}
}
return operations;
}
int main() {
auto start_time = chrono::high_resolution_clock::now();
rng.seed(chrono::duration_cast<chrono::nanoseconds>(start_time.time_since_epoch()).count());
input();
generateCircuit();
// 移動コストを確認
int move_cost = calculateMoveCost();
cerr << "Move cost per round: " << move_cost << endl;
cerr << "Max possible rounds: " << T / move_cost << endl;
Solution bestSolution = simulatedAnnealing();
vector<char> operations = generateOperations(bestSolution);
for (char op : operations) {
cout << op << endl;
}
return 0;
}
ぴぃいいいい