#include 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 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 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> get_tour(vector> &to_visit, int sx, int sy, int ex, int ey, int N) { // sx,syからex,eyまでのツアーを最短貪欲で求める vector tour; int cx = sx, cy = sy; set 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> res; for (int i = 0; i < tour.size(); ++i) { res.push_back(to_visit[tour[i]]); } return res; } vector get_ops(int sx, int sy, int ex, int ey) { vector 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; } int main() { ios::sync_with_stdio(false); cin.tie(NULL); int N, T; cin >> N >> T; vector> A(N + 1, vector(N + 1)); for (int i = 1; i <= N; ++i) for (int j = 1; j <= N; ++j) cin >> A[i][j]; vector ops; vector> base_list; vector> target_list; map, vector> op_list; // x=1 for (int i = 1; i <= N; ++i) { base_list.push_back({1, i}); } // x>1 for (int i = 2; i <= N; ++i) { for (int j = 1; j <= N; ++j) { target_list.push_back({i, j}); } } // target_listそれぞれで、基底(base_list)のXOR組み合わせで最も値が大きくなるものを選ぶ for (auto [x, y] : target_list) { int max_val = A[x][y]; vector 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(v, v + max_k); } }); } op_list[{x, y}] = op; cerr << "op_list[" << x << "][" << y << "]: "; for (auto k : op) { cerr << k << " "; } cerr << endl; int tmp = A[x][y]; cerr << "f: " << to_binary(tmp) << " (" << tmp << ")" << endl; for (auto k : op) { int before = tmp; tmp ^= A[base_list[k].first][base_list[k].second]; cerr << k << ": " << to_binary(before) << " (" << before << ") -> " << to_binary(tmp) << " (" << tmp << ")" << endl; } cerr << "final: " << to_binary(tmp) << " (" << tmp << ")" << endl; } // target_listから順番に、配っていく int cx = 1, cy = 1; for (int i = 0; i < base_list.size(); ++i) { // 行かなきゃいけない座標リスト vector> 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> 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 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を入れ替える target_list.clear(); // target_list をx = 1にする for (int i = 1; i <= N; ++i) { target_list.push_back({1, i}); } // base_list を x = 2にする base_list.clear(); for (int i = 1; i <= N; ++i) { base_list.push_back({2, i}); } // target_listそれぞれで、基底(base_list)のXOR組み合わせで最も値が大きくなるものを選ぶ for (auto [x, y] : target_list) { int max_val = A[x][y]; vector 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(v, v + max_k); } }); } op_list[{x, y}] = op; cerr << "op_list[" << x << "][" << y << "]: "; for (auto k : op) { cerr << k << " "; } cerr << endl; int tmp = A[x][y]; cerr << "f: " << to_binary(tmp) << " (" << tmp << ")" << endl; for (auto k : op) { int before = tmp; tmp ^= A[base_list[k].first][base_list[k].second]; cerr << k << ": " << to_binary(before) << " (" << before << ") -> " << to_binary(tmp) << " (" << tmp << ")" << endl; } cerr << "final: " << to_binary(tmp) << " (" << tmp << ")" << endl; } // target_listから順番に、配っていく for (int i = 0; i < base_list.size(); ++i) { // 行かなきゃいけない座標リスト vector> 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> 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 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'); } cerr << "ops.size(): " << ops.size() << endl; for (auto op : ops) cout << op << endl; return 0; }