結果
問題 |
No.5022 XOR Printer
|
ユーザー |
![]() |
提出日時 | 2025-07-26 16:36:58 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 1,983 ms / 2,000 ms |
コード長 | 13,491 bytes |
コンパイル時間 | 4,982 ms |
コンパイル使用メモリ | 343,360 KB |
実行使用メモリ | 7,720 KB |
スコア | 5,193,786,499 |
最終ジャッジ日時 | 2025-07-26 16:39:07 |
合計ジャッジ時間 | 107,122 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 50 |
ソースコード
// #pragma GCC optimize // "-O3,omit-frame-pointer,inline,unroll-all-loops,fast-math" #pragma GCC target // "tune=native" #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> using namespace std; // ==== Typedefs / utils ==== using u8 = uint8_t; using u32 = uint32_t; using u64 = uint64_t; using i64 = long long; struct RNG { uint64_t s[2]; RNG() { reset((uint64_t)chrono::steady_clock::now().time_since_epoch().count()); } static inline uint64_t rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } void reset(uint64_t seed) { auto sm = [s = seed]() mutable { s += 0x9E3779B97f4A7C15ull; u64 z = s; z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; return z ^ (z >> 31); }; s[0] = sm(); s[1] = sm(); } uint64_t next() { uint64_t s0 = s[0], s1 = s[1]; uint64_t r = rotl(s0 * 5, 7) * 9; s1 ^= s0; s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); s[1] = rotl(s1, 37); return r; } double randomDouble() { return (double)(uint32_t)next() / 4294967296.0; } uint32_t random32(uint32_t r) { return (uint64_t)(uint32_t)next() * r >> 32; } } rng; struct timer { chrono::high_resolution_clock::time_point t0; timer() { t0 = chrono::high_resolution_clock::now(); } float elapsed() const { return chrono::duration<float>(chrono::high_resolution_clock::now() - t0) .count(); } }; struct EvalResult { u64 sum = 0; vector<char> ops; vector<u32> Aflat; // final matrix (flattened by row-major) }; // ==== Simulator (fast eval + emitting version) ==== struct Simulator { int N, T, NN; // N=10, NN=100 vector<u32> A0; // flattened A vector<int> xr, yc; // coordinates per id vector<int> dist; // dist[a*NN + b] = Manhattan // MSB-based pruning for 1C array<vector<int>, 20> msb_bucket; // indices of cells with given MSB (0..19) array<array<vector<int>, 20>, 100> near_msb; // near_msb[target][bit] = top-L closest ids // working state (per simulation) vector<u32> A; // working grid (flattened) bitset<100> written; // whether W already done int cur; // current id u32 s; // register int used; // used turns inline int DID(int a, int b) const { return dist[a * NN + b]; } void init_precompute(int N_, int T_, const vector<vector<u32>> &A2d, int L = 12) { N = N_; T = T_; NN = N * N; A0.resize(NN); xr.resize(NN); yc.resize(NN); int id = 0; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) { A0[id] = A2d[i][j]; xr[id] = i; yc[id] = j; ++id; } // distances dist.assign(NN * NN, 0); for (int a = 0; a < NN; a++) for (int b = 0; b < NN; b++) dist[a * NN + b] = abs(xr[a] - xr[b]) + abs(yc[a] - yc[b]); // msb buckets for (int b = 0; b < 20; b++) msb_bucket[b].clear(); for (int i2 = 0; i2 < NN; i2++) { u32 v = A0[i2]; if (v == 0) continue; int b = 31 - __builtin_clz(v); if (0 <= b && b < 20) msb_bucket[b].push_back(i2); } // near_msb precompute for (int t = 0; t < NN; t++) { for (int b = 0; b < 20; b++) { auto &src = msb_bucket[b]; auto cmp = [&](int p, int q) { return DID(p, t) < DID(q, t); }; if (src.empty()) { near_msb[t][b].clear(); continue; } vector<int> tmp = src; if ((int)tmp.size() > L) { nth_element(tmp.begin(), tmp.begin() + L, tmp.end(), cmp); tmp.resize(L); sort(tmp.begin(), tmp.end(), cmp); } else { sort(tmp.begin(), tmp.end(), cmp); } near_msb[t][b] = move(tmp); } } } // candidate action for a target id, using current (cur, s, used) struct Cand { long long val; int cost; int mode; int pr; }; // mode: 0=0C, 1=1C, -1=none inline Cand best_action_for_target(int t) const { Cand best{LLONG_MIN, INT_MAX, -1, -1}; int rem = T - used; // 0C { int c0 = DID(cur, t) + 1; if (c0 <= rem) { u32 nv = (A[t] ^ s); if ((long long)nv > (long long)A[t]) { best = {(long long)nv, c0, 0, -1}; } } } // 1C: focus on first highest zero-bit of base u32 base = A[t] ^ s; int k = -1; for (int b = 19; b >= 0; --b) { if (((base >> b) & 1u) == 0u) { k = b; break; } } auto try_bucket = [&](int bit) { if (bit < 0) return; auto const &cand = near_msb[t][bit]; for (int pr : cand) { int c1 = DID(cur, pr) + 1 + DID(pr, t) + 1; if (c1 > rem) continue; u32 s2 = s ^ A[pr]; u32 nv = (A[t] ^ s2); if ((long long)nv <= (long long)A[t]) continue; if (nv > (u32)best.val || (nv == (u32)best.val && c1 < best.cost)) { best = {(long long)nv, c1, 1, pr}; } } }; if (k >= 0) { try_bucket(k); if (best.mode < 0) try_bucket(k - 1); } return best; } // --- FAST evaluation (no ops emission) --- u64 simulate_value(const vector<int> &order) { A = A0; written.reset(); cur = 0; s = 0; used = 0; bool progressed = true; while (progressed && used < T) { progressed = false; for (int id : order) { if (used >= T) break; if (written.test(id)) continue; Cand cand = best_action_for_target(id); if (cand.mode < 0) continue; if (cand.mode == 0) { // move -> W if (used + cand.cost > T) continue; used += DID(cur, id); cur = id; used += 1; // W A[id] ^= s; written.set(id); progressed = true; } else { // move pr -> C -> move t -> W if (used + cand.cost > T) continue; used += DID(cur, cand.pr); cur = cand.pr; used += 1; // C s ^= A[cand.pr]; used += DID(cur, id); cur = id; used += 1; // W A[id] ^= s; written.set(id); progressed = true; } } } u64 sum = 0; for (int i = 0; i < NN; i++) sum += A[i]; return sum; } // --- Full simulation with ops emission (UDLR + C/W) --- inline void emit_move_path(int from, int to, vector<char> &ops_out) { int dr = xr[to] - xr[from]; int dc = yc[to] - yc[from]; if (dr >= 0) for (int k = 0; k < dr; ++k) ops_out.push_back('D'); else for (int k = 0; k < -dr; ++k) ops_out.push_back('U'); if (dc >= 0) for (int k = 0; k < dc; ++k) ops_out.push_back('R'); else for (int k = 0; k < -dc; ++k) ops_out.push_back('L'); } EvalResult simulate_emit(const vector<int> &order) { A = A0; written.reset(); cur = 0; s = 0; used = 0; vector<char> ops_out; ops_out.reserve(6000); bool progressed = true; while (progressed && used < T) { progressed = false; for (int id : order) { if (used >= T) break; if (written.test(id)) continue; Cand cand = best_action_for_target(id); if (cand.mode < 0) continue; if (used + cand.cost > T) continue; if (cand.mode == 0) { // move to t emit_move_path(cur, id, ops_out); used += DID(cur, id); cur = id; // W ops_out.push_back('W'); ++used; A[id] ^= s; written.set(id); progressed = true; } else { // move to pr emit_move_path(cur, cand.pr, ops_out); used += DID(cur, cand.pr); cur = cand.pr; // C ops_out.push_back('C'); ++used; s ^= A[cand.pr]; // move to t emit_move_path(cur, id, ops_out); used += DID(cur, id); cur = id; // W ops_out.push_back('W'); ++used; A[id] ^= s; written.set(id); progressed = true; } } } EvalResult res; res.ops = move(ops_out); res.Aflat = A; res.sum = 0; for (int i = 0; i < NN; i++) res.sum += A[i]; return res; } }; // ==== Main with Simulated Annealing (adjacent swap / 2-point swap / 1-point // insertion) ==== int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, T; if (!(cin >> N >> T)) return 0; vector<vector<u32>> A2(N, vector<u32>(N)); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A2[i][j]; T = 1000; Simulator sim; sim.init_precompute(N, T, A2, /*L=*/12); vector<int> order(sim.NN); iota(order.begin(), order.end(), 0); timer tim; const double LIM = 1.98; const double T0 = 1e8, T1 = 1e-3; // initial u64 cur_sum = sim.simulate_value(order); u64 best_sum = cur_sum; vector<int> best_order = order; EvalResult best_emit = sim.simulate_emit(order); // initial feasible sequence // SA loop while (tim.elapsed() < LIM) { // temperature double ft = tim.elapsed() / LIM; double temp = T0 * pow(T1 / T0, ft); // Neighborhood: 0=adjacent swap, 1=two-point swap, 2=one-point // insertion vector<int> cand = order; u32 kind = rng.random32(3); if (kind == 0) { // adjacent swap if ((int)cand.size() >= 2) { int i = rng.random32((uint32_t)max(1, (int)cand.size() - 1)); swap(cand[i], cand[i + 1]); } } else if (kind == 1) { // two-point swap (i != j) int n = (int)cand.size(); if (n >= 2) { int i = rng.random32((uint32_t)n); int j = rng.random32((uint32_t)(n - 1)); if (j >= i) ++j; swap(cand[i], cand[j]); } } else { // one-point insertion int n = (int)cand.size(); int i = rng.random32((uint32_t)n); int j = rng.random32((uint32_t)(n - 1)); if (j >= i) ++j; // ensure j != i int v = cand[i]; if (i < j) { for (int k = i; k < j; ++k) cand[k] = cand[k + 1]; cand[j] = v; } else { for (int k = i; k > j; --k) cand[k] = cand[k - 1]; cand[j] = v; } } u64 cand_sum = sim.simulate_value(cand); long long delta = (long long)cand_sum - (long long)cur_sum; bool accept = (delta >= 0) || (rng.randomDouble() < exp(delta / temp)); if (accept) { order.swap(cand); cur_sum = cand_sum; if (cur_sum > best_sum) { best_sum = cur_sum; best_order = order; best_emit = sim.simulate_emit(best_order); // only for the best } } } // --- Debug output to stderr --- cerr << best_emit.ops.size() << '\n'; u64 out_sum = 0; for (int i = 0; i < sim.NN; i++) { cerr << best_emit.Aflat[i] << ((i % N == N - 1) ? '\n' : ' '); out_sum += best_emit.Aflat[i]; } cerr << out_sum << '\n'; // --- Answer (ops to stdout, one per line) --- for (char ch : best_emit.ops) cout << ch << '\n'; return 0; }