結果
| 問題 |
No.5022 XOR Printer
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-07-26 16:49:16 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,955 ms / 2,000 ms |
| コード長 | 10,577 bytes |
| コンパイル時間 | 5,444 ms |
| コンパイル使用メモリ | 367,008 KB |
| 実行使用メモリ | 7,716 KB |
| スコア | 5,095,529,890 |
| 最終ジャッジ日時 | 2025-07-26 16:51:04 |
| 合計ジャッジ時間 | 106,849 ms |
|
ジャッジサーバーID (参考情報) |
judge6 / judge5 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
コンパイルメッセージ
main.cpp: In function ‘int main()’:
main.cpp:319:23: warning: ‘void std::random_shuffle(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<pair<int, int>*, vector<pair<int, int> > >]’ is deprecated: use 'std::shuffle' instead [-Wdeprecated-declarations]
319 | random_shuffle(all.begin(), all.end());
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/13/algorithm:61,
from /usr/include/x86_64-linux-gnu/c++/13/bits/stdc++.h:51,
from main.cpp:2:
/usr/include/c++/13/bits/stl_algo.h:4581:5: note: declared here
4581 | random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last)
| ^~~~~~~~~~~~~~
ソースコード
#pragma GCC optimize("O3,Ofast,omit-frame-pointer,unroll-all-loops,tree-loop-vectorize,tree-slp-vectorize")
#include <bits/stdc++.h>
using namespace std;
string to_binary(int x) {
string res;
for (int i = 0; i < 20; ++i) {
res += (x & (1 << i)) ? '1' : '0';
}
reverse(res.begin(), res.end());
return res;
}
void recursive_comb(int *indexes, int s, int rest, std::function<void(int *)> f) {
if (rest == 0) {
f(indexes);
} else {
if (s < 0) return;
recursive_comb(indexes, s - 1, rest, f);
indexes[rest - 1] = s;
recursive_comb(indexes, s - 1, rest - 1, f);
}
}
// nCkの組み合わせに対して処理を実行する
void foreach_comb(int n, int k, std::function<void(int *)> f) {
int indexes[k];
recursive_comb(indexes, n - 1, k, f);
}
int dist(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
vector<pair<int, int>> get_tour(vector<pair<int, int>> &to_visit, int sx, int sy, int ex, int ey, int N) {
// sx,syからex,eyまでのツアーを最短貪欲で求める
vector<int> tour;
int cx = sx, cy = sy;
set<int> visited;
while (visited.size() < to_visit.size()) {
int min_dist = 1e9;
int min_idx = -1;
for (int i = 0; i < to_visit.size(); ++i) {
int nx = to_visit[i].first;
int ny = to_visit[i].second;
if (visited.count(i)) continue;
int d = dist(nx, ny, cx, cy);
if (d < min_dist) {
min_dist = d;
min_idx = i;
}
}
if (min_idx == -1) {
break;
}
tour.push_back(min_idx);
visited.insert(min_idx);
cx = to_visit[min_idx].first;
cy = to_visit[min_idx].second;
}
vector<pair<int, int>> res;
for (int i = 0; i < tour.size(); ++i) {
res.push_back(to_visit[tour[i]]);
}
return res;
}
vector<char> get_ops(int sx, int sy, int ex, int ey) {
vector<char> ops;
int cx = sx, cy = sy;
while (cx != ex || cy != ey) {
if (cx < ex) {
ops.push_back('D');
cx++;
} else if (cx > ex) {
ops.push_back('U');
cx--;
}
if (cy < ey) {
ops.push_back('R');
cy++;
} else if (cy > ey) {
ops.push_back('L');
cy--;
}
}
return ops;
}
pair<vector<char>, int> solve_greedy(vector<pair<int, int>> &target_list, vector<pair<int, int>> &base_list, vector<vector<int>> &_A, int N) {
vector<vector<int>> A = _A;
vector<char> ops;
map<pair<int, int>, vector<int>> op_list;
// target_listそれぞれで、基底(base_list)のXOR組み合わせで最も値が大きくなるものを選ぶ
for (auto [x, y] : target_list) {
int max_val = A[x][y];
vector<int> op;
for (int max_k = 1; max_k <= 2; ++max_k) {
foreach_comb(base_list.size(), max_k, [&](int *v) {
int val = A[x][y];
for (int k = 0; k < max_k; ++k) {
val ^= A[base_list[v[k]].first][base_list[v[k]].second];
}
if (val > max_val) {
max_val = val;
op = vector<int>(v, v + max_k);
}
});
}
op_list[{x, y}] = op;
}
// target_listから順番に、配っていく
int cx = 1, cy = 1;
for (int i = 0; i < base_list.size(); ++i) {
// 行かなきゃいけない座標リスト
vector<pair<int, int>> to_visit;
for (auto [x, y] : target_list) {
bool found = false;
for (auto op : op_list[{x, y}]) {
if (op == i) {
found = true;
break;
}
}
if (found) {
to_visit.push_back({x, y});
}
}
int tx = base_list[i].first, ty = base_list[i].second;
// opsにget_ops(cx, cy, tx, ty)を追加
for (auto op : get_ops(cx, cy, tx, ty)) {
ops.push_back(op);
}
cx = tx;
cy = ty;
assert(cx >= 1 && cx <= N && cy >= 1 && cy <= N);
assert(tx >= 1 && tx <= N && ty >= 1 && ty <= N);
vector<pair<int, int>> tour = get_tour(to_visit, tx, ty, tx, ty, N);
ops.push_back('C');
int cur = A[tx][ty];
for (auto [x, y] : tour) {
vector<char> path = get_ops(cx, cy, x, y);
assert(x >= 1 && x <= N && y >= 1 && y <= N);
for (auto op : path) {
ops.push_back(op);
}
cx = x;
cy = y;
ops.push_back('W');
A[cx][cy] ^= cur;
}
for (auto op : get_ops(cx, cy, tx, ty)) {
ops.push_back(op);
}
cx = tx;
cy = ty;
ops.push_back('C');
}
// target_listをbase_listにする
vector<pair<int, int>> new_target_list;
new_target_list = base_list;
// base_list をtarget_listから10個選ぶ
base_list.clear();
for (int i = 0; i < new_target_list.size(); ++i) {
base_list.push_back(target_list[i]);
}
target_list = new_target_list;
// target_listそれぞれで、基底(base_list)のXOR組み合わせで最も値が大きくなるものを選ぶ
for (auto [x, y] : target_list) {
int max_val = A[x][y];
vector<int> op;
for (int max_k = 1; max_k <= 4; ++max_k) {
foreach_comb(base_list.size(), max_k, [&](int *v) {
int val = A[x][y];
for (int k = 0; k < max_k; ++k) {
val ^= A[base_list[v[k]].first][base_list[v[k]].second];
}
if (val > max_val) {
max_val = val;
op = vector<int>(v, v + max_k);
}
});
}
op_list[{x, y}] = op;
}
// target_listから順番に、配っていく
for (int i = 0; i < base_list.size(); ++i) {
// 行かなきゃいけない座標リスト
vector<pair<int, int>> to_visit;
for (auto [x, y] : target_list) {
bool found = false;
for (auto op : op_list[{x, y}]) {
if (op == i) {
found = true;
break;
}
}
if (found) {
to_visit.push_back({x, y});
}
}
int tx = base_list[i].first, ty = base_list[i].second;
// opsにget_ops(cx, cy, tx, ty)を追加
for (auto op : get_ops(cx, cy, tx, ty)) {
ops.push_back(op);
}
cx = tx;
cy = ty;
assert(cx >= 1 && cx <= N && cy >= 1 && cy <= N);
assert(tx >= 1 && tx <= N && ty >= 1 && ty <= N);
vector<pair<int, int>> tour = get_tour(to_visit, tx, ty, tx, ty, N);
ops.push_back('C');
int cur = A[tx][ty];
for (auto [x, y] : tour) {
vector<char> path = get_ops(cx, cy, x, y);
assert(x >= 1 && x <= N && y >= 1 && y <= N);
for (auto op : path) {
ops.push_back(op);
}
cx = x;
cy = y;
ops.push_back('W');
A[cx][cy] ^= cur;
}
for (auto op : get_ops(cx, cy, tx, ty)) {
ops.push_back(op);
}
cx = tx;
cy = ty;
ops.push_back('C');
}
// sum of A
int score = 0;
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
score += A[i][j];
}
}
return {ops, score};
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int N, T;
cin >> N >> T;
vector<vector<int>> A(N + 1, vector<int>(N + 1));
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j)
cin >> A[i][j];
chrono::system_clock::time_point start = chrono::system_clock::now();
vector<char> best_ops;
int best_score = 0;
for (int base_x = 1; base_x <= N; ++base_x) {
vector<pair<int, int>> base_list;
vector<pair<int, int>> target_list;
// x=base_x
for (int y = 1; y <= N; ++y) {
base_list.push_back({base_x, y});
}
// x!=base_x
for (int x = 1; x <= N; ++x) {
for (int y = 1; y <= N; ++y) {
if (x == base_x) continue;
target_list.push_back({x, y});
}
}
auto [ops, score] = solve_greedy(target_list, base_list, A, N);
if (score > best_score && ops.size() <= T) {
best_score = score;
best_ops = ops;
}
}
for (int base_y = 1; base_y <= N; ++base_y) {
vector<pair<int, int>> base_list;
vector<pair<int, int>> target_list;
// y=base_y
for (int x = 1; x <= N; ++x) {
base_list.push_back({x, base_y});
}
// y!=base_y
for (int x = 1; x <= N; ++x) {
for (int y = 1; y <= N; ++y) {
if (y == base_y) continue;
target_list.push_back({x, y});
}
}
auto [ops, score] = solve_greedy(target_list, base_list, A, N);
if (score > best_score && ops.size() <= T) {
best_score = score;
best_ops = ops;
}
}
vector<pair<int, int>> all;
for (int x = 1; x <= N; ++x) {
for (int y = 1; y <= N; ++y) {
all.push_back({x, y});
}
}
// 残り時間いっぱい、base_listを乱択で選んで、それぞれで貪欲
while (chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - start).count() < 1950) {
random_shuffle(all.begin(), all.end());
int pick_num = rand() % 10 + 5;
// 最初のrandom(5,15)個をbase_listにする
vector<pair<int, int>> base_list;
for (int i = 0; i < pick_num; ++i) {
base_list.push_back(all[i]);
}
vector<pair<int, int>> target_list;
for (int i = pick_num; i < all.size(); ++i) {
target_list.push_back(all[i]);
}
auto [ops, score] = solve_greedy(target_list, base_list, A, N);
if (score > best_score && ops.size() <= T) {
best_score = score;
best_ops = ops;
}
}
cerr << "ops.size(): " << best_ops.size() << endl;
cerr << "score: " << best_score << endl;
for (auto op : best_ops) cout << op << endl;
return 0;
}