{"model_name":"gpt-5.2-high","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    // inclusive\n    int rand_int(int l, int r) {\n        if (l > r) return l;\n        uint64_t range = (uint64_t)(r - l + 1);\n        return l + (int)(next_u64() % range);\n    }\n    double rand01() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nstruct Solver {\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<Rect> rect;\n    vector<double> p;     // current satisfaction per rect\n    double sumP = 0.0;\n\n    SplitMix64 rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n); y.resize(n); r.resize(n);\n        for (int i = 0; i < n; i++) cin >> x[i] >> y[i] >> r[i];\n\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = SplitMix64(seed);\n\n        rect.resize(n);\n        for (int i = 0; i < n; i++) {\n            rect[i] = Rect{x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        p.assign(n, 0.0);\n        recompute_all_scores();\n    }\n\n    long long area(const Rect& R) const {\n        return 1LL * (R.c - R.a) * (R.d - R.b);\n    }\n\n    bool contains_point(int i, const Rect& R) const {\n        return (R.a <= x[i] && x[i] < R.c && R.b <= y[i] && y[i] < R.d);\n    }\n\n    double satisfaction(int i, const Rect& R) const {\n        if (!contains_point(i, R)) return 0.0;\n        long long s = area(R);\n        long long ri = r[i];\n        long long mn = min(ri, s);\n        long long mx = max(ri, s);\n        double ratio = (double)mn / (double)mx;\n        double t = 1.0 - ratio;\n        return 1.0 - t * t;\n    }\n\n    void recompute_all_scores() {\n        sumP = 0.0;\n        for (int i = 0; i < n; i++) {\n            p[i] = satisfaction(i, rect[i]);\n            sumP += p[i];\n        }\n    }\n\n    // For rectangle i, compute nearest blockers in x-direction given its current y-interval.\n    // leftLimit: maximum c_j among rectangles with y-overlap and located to the left (c_j <= a_i)\n    // rightLimit: minimum a_j among rectangles with y-overlap and located to the right (a_j >= c_i)\n    void compute_x_limits(int i, int &leftLimit, int &rightLimit) const {\n        const Rect& R = rect[i];\n        leftLimit = 0;\n        rightLimit = 10000;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = rect[j];\n            if (!overlap1D(R.b, R.d, Q.b, Q.d)) continue; // no y-overlap => cannot collide by x move\n            if (Q.c <= R.a) leftLimit = max(leftLimit, Q.c);\n            if (R.c <= Q.a) rightLimit = min(rightLimit, Q.a);\n        }\n    }\n\n    // For rectangle i, compute nearest blockers in y-direction given its current x-interval.\n    void compute_y_limits(int i, int &downLimit, int &upLimit) const {\n        const Rect& R = rect[i];\n        downLimit = 0;\n        upLimit = 10000;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = rect[j];\n            if (!overlap1D(R.a, R.c, Q.a, Q.c)) continue; // no x-overlap => cannot collide by y move\n            if (Q.d <= R.b) downLimit = max(downLimit, Q.d);\n            if (R.d <= Q.b) upLimit = min(upLimit, Q.b);\n        }\n    }\n\n    // Feasible inclusive range for one side move; returns false if no move possible (range only equals current).\n    // dir: 0=left(a),1=right(c),2=bottom(b),3=top(d)\n    bool feasible_range(int i, int dir, int &low, int &high) const {\n        const Rect& R = rect[i];\n        if (dir == 0) {\n            int L, RR; compute_x_limits(i, L, RR);\n            low = L;\n            high = min(x[i], R.c - 1);\n        } else if (dir == 1) {\n            int L, RR; compute_x_limits(i, L, RR);\n            low = max(x[i] + 1, R.a + 1);\n            high = RR;\n        } else if (dir == 2) {\n            int D, U; compute_y_limits(i, D, U);\n            low = D;\n            high = min(y[i], R.d - 1);\n        } else {\n            int D, U; compute_y_limits(i, D, U);\n            low = max(y[i] + 1, R.b + 1);\n            high = U;\n        }\n        if (low > high) return false;\n        return true;\n    }\n\n    int desired_side_value(int i, int dir, int low, int high) const {\n        const Rect& R = rect[i];\n        long long ri = r[i];\n        if (dir == 0 || dir == 1) {\n            int h = R.d - R.b;\n            long long desiredW = (ri + h / 2) / h;\n            desiredW = max<long long>(1, min<long long>(10000, desiredW));\n            if (dir == 0) {\n                long long desA = (long long)R.c - desiredW;\n                desA = max<long long>(low, min<long long>(high, desA));\n                return (int)desA;\n            } else {\n                long long desC = (long long)R.a + desiredW;\n                desC = max<long long>(low, min<long long>(high, desC));\n                return (int)desC;\n            }\n        } else {\n            int w = R.c - R.a;\n            long long desiredH = (ri + w / 2) / w;\n            desiredH = max<long long>(1, min<long long>(10000, desiredH));\n            if (dir == 2) {\n                long long desB = (long long)R.d - desiredH;\n                desB = max<long long>(low, min<long long>(high, desB));\n                return (int)desB;\n            } else {\n                long long desD = (long long)R.b + desiredH;\n                desD = max<long long>(low, min<long long>(high, desD));\n                return (int)desD;\n            }\n        }\n    }\n\n    Rect with_side(const Rect& R, int dir, int val) const {\n        Rect T = R;\n        if (dir == 0) T.a = val;\n        else if (dir == 1) T.c = val;\n        else if (dir == 2) T.b = val;\n        else T.d = val;\n        return T;\n    }\n\n    // Greedy single-rectangle improvement: try setting one side to (desired,low,high) and take best improvement.\n    bool greedy_improve_one(int i) {\n        double cur = p[i];\n        Rect bestR = rect[i];\n        double best = cur;\n\n        for (int dir = 0; dir < 4; dir++) {\n            int low, high;\n            if (!feasible_range(i, dir, low, high)) continue;\n\n            int curVal = (dir==0? rect[i].a : dir==1? rect[i].c : dir==2? rect[i].b : rect[i].d);\n            if (low == high && low == curVal) continue;\n\n            int des = desired_side_value(i, dir, low, high);\n            int candidates[3] = {des, low, high};\n            for (int k = 0; k < 3; k++) {\n                int v = candidates[k];\n                if (v == curVal) continue;\n                Rect cand = with_side(rect[i], dir, v);\n                // Must remain valid and contain point (range logic should ensure it).\n                if (!contains_point(i, cand)) continue;\n                if (cand.a < 0 || cand.b < 0 || cand.c > 10000 || cand.d > 10000) continue;\n                if (cand.a >= cand.c || cand.b >= cand.d) continue;\n                double sc = satisfaction(i, cand);\n                if (sc > best + 1e-12) {\n                    best = sc;\n                    bestR = cand;\n                }\n            }\n        }\n\n        if (best > cur + 1e-12) {\n            rect[i] = bestR;\n            sumP += (best - p[i]);\n            p[i] = best;\n            return true;\n        }\n        return false;\n    }\n\n    void greedy_init() {\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) { return r[a] > r[b]; });\n\n        // Several passes until no change.\n        for (int pass = 0; pass < 30; pass++) {\n            bool any = false;\n            for (int idx = 0; idx < n; idx++) {\n                int i = order[idx];\n                // a few local steps\n                for (int rep = 0; rep < 3; rep++) {\n                    if (!greedy_improve_one(i)) break;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        // Random greedy polishing\n        for (int it = 0; it < 40000; it++) {\n            int i = (int)(rng.next_u32() % n);\n            greedy_improve_one(i);\n        }\n    }\n\n    void simulated_annealing(double timeLimitSec) {\n        auto start = chrono::steady_clock::now();\n        auto elapsedSec = [&]() -> double {\n            return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        };\n\n        vector<Rect> bestRect = rect;\n        vector<double> bestP = p;\n        double bestSum = sumP;\n\n        const double T0 = 0.05;\n        const double T1 = 0.001;\n\n        long long iterations = 0;\n\n        while (true) {\n            double t = elapsedSec();\n            if (t >= timeLimitSec) break;\n            double prog = t / timeLimitSec;\n            double T = T0 * pow(T1 / T0, prog);\n\n            int i = (int)(rng.next_u32() % n);\n            int dir = (int)(rng.next_u32() & 3);\n\n            int low, high;\n            if (!feasible_range(i, dir, low, high)) continue;\n\n            int curVal = (dir==0? rect[i].a : dir==1? rect[i].c : dir==2? rect[i].b : rect[i].d);\n            if (low == high) continue;\n            if (curVal < low || curVal > high) {\n                // Shouldn't happen, but guard.\n                curVal = max(low, min(high, curVal));\n            }\n\n            int des = desired_side_value(i, dir, low, high);\n\n            int candVal;\n            if (rng.rand01() < 0.75) {\n                int span = max(1, (high - low) / 10);\n                candVal = des + rng.rand_int(-span, span);\n                candVal = max(low, min(high, candVal));\n            } else {\n                candVal = rng.rand_int(low, high);\n            }\n            if (candVal == curVal) continue;\n\n            Rect oldR = rect[i];\n            double oldP = p[i];\n\n            Rect newR = with_side(oldR, dir, candVal);\n            if (!contains_point(i, newR)) continue;\n            if (newR.a >= newR.c || newR.b >= newR.d) continue;\n\n            double newP = satisfaction(i, newR);\n            double delta = newP - oldP;\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double prob = exp(delta / T);\n                if (rng.rand01() < prob) accept = true;\n            }\n\n            if (accept) {\n                rect[i] = newR;\n                p[i] = newP;\n                sumP += delta;\n\n                if (sumP > bestSum + 1e-12) {\n                    bestSum = sumP;\n                    bestRect = rect;\n                    bestP = p;\n                }\n            }\n\n            iterations++;\n        }\n\n        rect = bestRect;\n        p = bestP;\n        sumP = bestSum;\n    }\n\n    void solve() {\n        // 1) Greedy initialization (fast, improves a lot over 1x1)\n        greedy_init();\n\n        // 2) SA refinement\n        simulated_annealing(4.90);\n\n        // Output\n        for (int i = 0; i < n; i++) {\n            cout << rect[i].a << ' ' << rect[i].b << ' ' << rect[i].c << ' ' << rect[i].d << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50, W = 50, N = H * W;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // 2^53\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Result {\n    vector<int> path; // sequence of square indices\n    int score = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    cin >> si >> sj;\n\n    vector<int> tile(N);\n    int maxTile = 0;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t;\n            cin >> t;\n            tile[i * W + j] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    int M = maxTile + 1;\n\n    vector<int> val(N);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int p;\n            cin >> p;\n            val[i * W + j] = p;\n        }\n    }\n\n    // Build adjacency between squares BUT only if they are in different tiles\n    array<vector<int>, N> adj;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = i * W + j;\n            static const int di[4] = {-1, 1, 0, 0};\n            static const int dj[4] = {0, 0, -1, 1};\n            for (int k = 0; k < 4; k++) {\n                int ni = i + di[k], nj = j + dj[k];\n                if (ni < 0 || ni >= H || nj < 0 || nj >= W) continue;\n                int v = ni * W + nj;\n                if (tile[u] == tile[v]) continue; // moving within same tile is forbidden anyway\n                adj[u].push_back(v);\n            }\n        }\n    }\n\n    const int start = si * W + sj;\n\n    // stamp-based \"used tile\" set\n    vector<int> usedStamp(M, 0);\n    int stamp = 0;\n\n    auto build_from_prefix = [&](const vector<int>& prefix, double alpha, double gamma, XorShift64 &rng) -> Result {\n        stamp++;\n        int st = stamp;\n\n        Result res;\n        res.path = prefix;\n        res.path.reserve(N);\n\n        int scoreSum = 0;\n        for (int v : prefix) {\n            usedStamp[tile[v]] = st;\n            scoreSum += val[v];\n        }\n\n        auto deg_unvisited = [&](int v) -> int {\n            int d = 0;\n            for (int to : adj[v]) {\n                if (usedStamp[tile[to]] != st) d++;\n            }\n            return d;\n        };\n\n        int cur = res.path.back();\n        while (true) {\n            // candidates up to 4\n            struct Cand { int v; double e; };\n            Cand cands[4];\n            int m = 0;\n\n            for (int nb : adj[cur]) {\n                int tnb = tile[nb];\n                if (usedStamp[tnb] == st) continue;\n\n                int deg1 = 0;\n                for (int nn : adj[nb]) {\n                    if (usedStamp[tile[nn]] != st) deg1++;\n                }\n\n                // 2-step lookahead: best next-next value after choosing nb\n                double best2 = 0.0;\n                for (int nn : adj[nb]) {\n                    int tnn = tile[nn];\n                    if (usedStamp[tnn] == st) continue;\n                    // degree at nn AFTER visiting nb (so tile[nb] becomes forbidden)\n                    int deg2 = 0;\n                    for (int x : adj[nn]) {\n                        int tx = tile[x];\n                        if (tx == tnb) continue;\n                        if (usedStamp[tx] != st) deg2++;\n                    }\n                    double cand2 = val[nn] + alpha * deg2;\n                    if (cand2 > best2) best2 = cand2;\n                }\n\n                double e = val[nb] + alpha * deg1 + gamma * best2;\n\n                // discourage immediate dead ends unless necessary\n                if (deg1 == 0) e -= 35.0;\n\n                // tiny noise for tie-breaking / diversification\n                e += rng.next_double() * 1e-3;\n\n                cands[m++] = {nb, e};\n            }\n\n            if (m == 0) break;\n\n            // sort m<=4 by e descending (simple selection)\n            for (int i = 0; i < m; i++) {\n                int best = i;\n                for (int j = i + 1; j < m; j++) {\n                    if (cands[j].e > cands[best].e) best = j;\n                }\n                swap(cands[i], cands[best]);\n            }\n\n            int pickRank = 0;\n            if (m >= 2) {\n                double u = rng.next_double();\n                if (u < 0.75) pickRank = 0;\n                else if (u < 0.93) pickRank = 1;\n                else pickRank = min(2, m - 1);\n            }\n\n            int nxt = cands[pickRank].v;\n            usedStamp[tile[nxt]] = st;\n            res.path.push_back(nxt);\n            scoreSum += val[nxt];\n            cur = nxt;\n        }\n\n        res.score = scoreSum;\n        return res;\n    };\n\n    auto now = chrono::steady_clock::now;\n    const double TIME_LIMIT = 1.95;\n    auto t0 = now();\n\n    XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multi-start randomized greedy to get a good initial best\n    Result best;\n    best.path = {start};\n    best.score = val[start];\n\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > 0.25) break;\n\n        double alpha = 8.0 + 18.0 * rng.next_double();  // [8,26]\n        double gamma = 0.10 + 0.55 * rng.next_double(); // [0.10,0.65]\n        Result r = build_from_prefix(vector<int>{start}, alpha, gamma, rng);\n        if (r.score > best.score) best = std::move(r);\n    }\n\n    // Simulated annealing with cut-and-regrow\n    Result cur = best;\n\n    int iter = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > TIME_LIMIT) break;\n        iter++;\n\n        // occasionally restart from best to keep search stable\n        if (iter % 450 == 0) cur = best;\n\n        int L = (int)cur.path.size();\n        int k = 0;\n        if (L <= 1) {\n            k = 0;\n        } else {\n            double u = rng.next_double();\n            if (u < 0.70) {\n                int lo = max(0, L - 1 - 220);\n                k = rng.next_int(lo, L - 1);\n            } else {\n                k = rng.next_int(0, L - 1);\n            }\n        }\n\n        vector<int> prefix;\n        prefix.reserve(k + 1);\n        prefix.insert(prefix.end(), cur.path.begin(), cur.path.begin() + (k + 1));\n\n        double alpha = 7.0 + 20.0 * rng.next_double();  // [7,27]\n        double gamma = 0.05 + 0.70 * rng.next_double(); // [0.05,0.75]\n        Result nxt = build_from_prefix(prefix, alpha, gamma, rng);\n\n        int delta = nxt.score - cur.score;\n\n        // temperature schedule by time\n        double tr = elapsed / TIME_LIMIT;\n        double T0 = 350.0, Tend = 2.0;\n        double T = T0 * pow(Tend / T0, tr);\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (accept) cur = std::move(nxt);\n        if (cur.score > best.score) best = cur;\n    }\n\n    // Output path as directions\n    string out;\n    out.reserve(best.path.size() ? best.path.size() - 1 : 0);\n    for (int i = 1; i < (int)best.path.size(); i++) {\n        int a = best.path[i - 1], b = best.path[i];\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (bi == ai - 1 && bj == aj) out.push_back('U');\n        else if (bi == ai + 1 && bj == aj) out.push_back('D');\n        else if (bi == ai && bj == aj - 1) out.push_back('L');\n        else if (bi == ai && bj == aj + 1) out.push_back('R');\n        else {\n            // should never happen\n            // fallback: output what we have\n            break;\n        }\n    }\n\n    cout << out << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horiz; // true: horizontal h[i][j] between (i,j)-(i,j+1), false: vertical v[i][j] between (i,j)-(i+1,j)\n    int i, j;\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int HW = 29; // horizontal edges per row\nstatic constexpr int VH = 29; // vertical edges per col\n\nstruct Solver {\n    // Estimated weights\n    double h[N][HW];\n    double v[VH][N];\n\n    // Visit counts (for exploration bonus)\n    int hc[N][HW];\n    int vc[VH][N];\n\n    vector<EdgeRef> last_edges;\n    double last_pred = 0.0;\n    int k = 0; // number of processed feedbacks\n\n    Solver() {\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n            h[i][j] = 5000.0;\n            hc[i][j] = 0;\n        }\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n            v[i][j] = 5000.0;\n            vc[i][j] = 0;\n        }\n    }\n\n    static inline double clampd(double x, double lo, double hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    inline double &edgeRef(const EdgeRef &e) {\n        return e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n    }\n    inline int &cntRef(const EdgeRef &e) {\n        return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n    }\n\n    // Base (non-exploration) estimated weight for move u->w\n    inline double baseWeight(int u, int w, EdgeRef &eref_out) {\n        int ui = u / N, uj = u % N;\n        int wi = w / N, wj = w % N;\n        if (ui == wi) {\n            // horizontal\n            if (wj == uj + 1) {\n                eref_out = {true, ui, uj};\n                return h[ui][uj];\n            } else {\n                // wj == uj - 1\n                eref_out = {true, ui, wj};\n                return h[ui][wj];\n            }\n        } else {\n            // vertical\n            if (wi == ui + 1) {\n                eref_out = {false, ui, uj};\n                return v[ui][uj];\n            } else {\n                // wi == ui - 1\n                eref_out = {false, wi, uj};\n                return v[wi][uj];\n            }\n        }\n    }\n\n    // Exploration-modified weight for Dijkstra at query index qk\n    inline double planWeight(const EdgeRef &e, int qk) const {\n        const double base = e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n        const int cnt = e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n\n        // Exploration fades out in first ~300 queries\n        double phase = 0.0;\n        if (qk < 300) phase = (300.0 - qk) / 300.0; // 1 -> 0\n        double explore = 0.6 * phase; // hyperparameter\n\n        // Make rarely-used edges slightly cheaper early\n        double denom = 1.0 + explore / sqrt(cnt + 1.0);\n        double w = base / denom;\n\n        // Keep weights positive and reasonable\n        w = clampd(w, 500.0, 12000.0);\n        return w;\n    }\n\n    // Dijkstra to get a path (full 4-neighbor), returns node list s..t\n    vector<int> shortestPathNodes(int si, int sj, int ti, int tj, int qk, double explore_scale_override = -1.0) {\n        int s = si * N + sj;\n        int t = ti * N + tj;\n\n        vector<double> dist(N * N, 1e100);\n        vector<int> prev(N * N, -1);\n\n        using P = pair<double,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == t) break;\n\n            int ui = u / N, uj = u % N;\n            auto relax = [&](int w) {\n                EdgeRef e;\n                // Need EdgeRef to compute weight; baseWeight fills e\n                (void)baseWeight(u, w, e);\n                double ww;\n\n                if (explore_scale_override >= 0.0) {\n                    // same shape as planWeight but scale can be forced smaller\n                    const double base = e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n                    const int cnt = e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n                    double phase = 0.0;\n                    if (qk < 300) phase = (300.0 - qk) / 300.0;\n                    double explore = explore_scale_override * phase;\n                    double denom = 1.0 + explore / sqrt(cnt + 1.0);\n                    ww = clampd(base / denom, 500.0, 12000.0);\n                } else {\n                    ww = planWeight(e, qk);\n                }\n\n                double nd = d + ww;\n                if (nd < dist[w]) {\n                    dist[w] = nd;\n                    prev[w] = u;\n                    pq.push({nd, w});\n                }\n            };\n\n            if (uj + 1 < N) relax(u + 1);\n            if (uj - 1 >= 0) relax(u - 1);\n            if (ui + 1 < N) relax(u + N);\n            if (ui - 1 >= 0) relax(u - N);\n        }\n\n        // reconstruct\n        vector<int> nodes;\n        int cur = t;\n        while (cur != -1) {\n            nodes.push_back(cur);\n            if (cur == s) break;\n            cur = prev[cur];\n        }\n        reverse(nodes.begin(), nodes.end());\n        return nodes;\n    }\n\n    // Build path string and record last_edges + last_pred\n    string buildPathAndRecord(const vector<int> &nodes) {\n        last_edges.clear();\n        last_pred = 0.0;\n        string path;\n        path.reserve(nodes.size() ? nodes.size()-1 : 0);\n\n        for (int idx = 0; idx + 1 < (int)nodes.size(); idx++) {\n            int a = nodes[idx];\n            int b = nodes[idx + 1];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            if (bi == ai && bj == aj + 1) path.push_back('R');\n            else if (bi == ai && bj == aj - 1) path.push_back('L');\n            else if (bi == ai + 1 && bj == aj) path.push_back('D');\n            else if (bi == ai - 1 && bj == aj) path.push_back('U');\n            else {\n                // should never happen\n                path.push_back('R');\n            }\n\n            EdgeRef e;\n            double w = baseWeight(a, b, e);\n            last_edges.push_back(e);\n            last_pred += w;\n        }\n        last_pred = max(last_pred, 1.0); // safety\n        return path;\n    }\n\n    string query(int si, int sj, int ti, int tj) {\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        // Primary attempt with exploration\n        vector<int> nodes = shortestPathNodes(si, sj, ti, tj, k);\n        // Safety: avoid crazy-long exploratory detours\n        if ((int)nodes.size() - 1 > manhattan + 60) {\n            nodes = shortestPathNodes(si, sj, ti, tj, k, /*explore_scale_override=*/0.2);\n        }\n        if ((int)nodes.size() - 1 > manhattan + 80) {\n            nodes = shortestPathNodes(si, sj, ti, tj, k, /*explore_scale_override=*/0.0);\n        }\n\n        return buildPathAndRecord(nodes);\n    }\n\n    void smoothOnce(double s) {\n        // Smooth horizontal along each row\n        for (int i = 0; i < N; i++) {\n            double tmp[HW];\n            for (int j = 0; j < HW; j++) {\n                double a = h[i][j];\n                double b = (j > 0 ? h[i][j-1] : h[i][j]);\n                double c = (j + 1 < HW ? h[i][j+1] : h[i][j]);\n                tmp[j] = (a + b + c) / 3.0;\n            }\n            for (int j = 0; j < HW; j++) {\n                h[i][j] = (1.0 - s) * h[i][j] + s * tmp[j];\n                h[i][j] = clampd(h[i][j], 500.0, 12000.0);\n            }\n        }\n\n        // Smooth vertical along each column\n        for (int j = 0; j < N; j++) {\n            double tmp[VH];\n            for (int i = 0; i < VH; i++) {\n                double a = v[i][j];\n                double b = (i > 0 ? v[i-1][j] : v[i][j]);\n                double c = (i + 1 < VH ? v[i+1][j] : v[i][j]);\n                tmp[i] = (a + b + c) / 3.0;\n            }\n            for (int i = 0; i < VH; i++) {\n                v[i][j] = (1.0 - s) * v[i][j] + s * tmp[i];\n                v[i][j] = clampd(v[i][j], 500.0, 12000.0);\n            }\n        }\n    }\n\n    void feedback(long long observed) {\n        // observed ~= last_pred * noise, noise in [0.9,1.1]\n        double ratio = (double)observed / last_pred;\n        ratio = clampd(ratio, 0.85, 1.18); // robust against outliers\n\n        // learning rate schedule: larger early, smaller later\n        double t = (double)k / 1000.0;\n        double lr = 0.35 * (1.0 - t) + 0.08; // ~0.43 -> ~0.08\n        double mul = 1.0 + lr * (ratio - 1.0);\n\n        // Update only used edges (and increase counts)\n        for (auto &e : last_edges) {\n            double &w = edgeRef(e);\n            int &c = cntRef(e);\n            w *= mul;\n            w = clampd(w, 500.0, 12000.0);\n            c++;\n        }\n\n        // Optional: tiny global scaling early to fix overall magnitude faster\n        if (k < 50) {\n            double glr = 0.02;\n            double gmul = 1.0 + glr * (ratio - 1.0);\n            for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n                h[i][j] = clampd(h[i][j] * gmul, 500.0, 12000.0);\n            }\n            for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n                v[i][j] = clampd(v[i][j] * gmul, 500.0, 12000.0);\n            }\n        }\n\n        // Periodic smoothing (matches \u201cmostly constant with local noise\u201d)\n        if (k % 5 == 4) {\n            smoothOnce(0.05);\n        }\n\n        k++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; q++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        string path = solver.query(si, sj, ti, tj);\n        cout << path << \"\\n\" << flush;\n\n        long long res;\n        cin >> res;\n        solver.feedback(res);\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr uint8_t DOT = 8; // internal '.' marker\n\n// --------- fast RNG (splitmix64) ----------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        // 53-bit mantissa\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Hasher {\n    size_t operator()(uint64_t x) const noexcept {\n        // splitmix64 hash\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        x = x ^ (x >> 31);\n        return (size_t)x;\n    }\n};\n\nusing FlatMap = boost::unordered_flat_map<uint64_t, int, Hasher>;\n\n// code = (len<<36) | bits, bits uses 3 bits per char, left-to-right.\nstatic inline uint64_t encodeVec(const vector<uint8_t>& v, int st, int len) {\n    uint64_t bits = 0;\n    for (int i = 0; i < len; i++) bits = (bits << 3) | (uint64_t)v[st + i];\n    return (uint64_t(len) << 36) | bits;\n}\nstatic inline uint64_t encodeFull(const vector<uint8_t>& v) {\n    return encodeVec(v, 0, (int)v.size());\n}\nstatic inline vector<uint8_t> decodeCode(uint64_t code) {\n    int len = int(code >> 36);\n    uint64_t bits = code & ((len == 0) ? 0ULL : ((1ULL << (3 * len)) - 1ULL));\n    vector<uint8_t> v(len);\n    for (int i = len - 1; i >= 0; i--) {\n        v[i] = uint8_t(bits & 7ULL);\n        bits >>= 3;\n    }\n    return v;\n}\n\nstruct CodeBook {\n    int minLen = 2, maxLen = 12;\n    FlatMap code2idx;\n    vector<int> weight;         // per idx\n    vector<uint64_t> codes;     // per idx\n    vector<vector<uint8_t>> pattern; // optional (used in phase2)\n    long long totalWeight = 0;  // sum of weights\n};\n\nstatic CodeBook makeCodeBook(const FlatMap& wmap, int minLen, int maxLen, bool storePattern) {\n    CodeBook book;\n    book.minLen = minLen;\n    book.maxLen = maxLen;\n    book.code2idx.reserve(wmap.size() * 2 + 8);\n\n    book.weight.reserve(wmap.size());\n    book.codes.reserve(wmap.size());\n    if (storePattern) book.pattern.reserve(wmap.size());\n\n    int idx = 0;\n    long long sum = 0;\n    for (auto &kv : wmap) {\n        uint64_t code = kv.first;\n        int w = kv.second;\n        book.code2idx.emplace(code, idx++);\n        book.codes.push_back(code);\n        book.weight.push_back(w);\n        sum += w;\n    }\n    book.totalWeight = sum;\n\n    if (storePattern) {\n        book.pattern.resize(book.codes.size());\n        for (int i = 0; i < (int)book.codes.size(); i++) {\n            book.pattern[i] = decodeCode(book.codes[i]);\n        }\n    }\n    return book;\n}\n\nstruct SAState {\n    array<array<uint8_t, N>, N> *mat = nullptr;\n    const CodeBook* book = nullptr;\n\n    // occ[idx] = total occurrences (across all 40 lines, all starts) in current matrix\n    vector<int> occ;\n    long long score = 0; // sum weight[idx] for occ[idx]>0\n\n    array<vector<int>, 40> lineIdx; // for each line, list of idx (with multiplicity) of matched codes\n\n    // temp buffers to avoid reallocs in inner loop\n    vector<int> tmpA, tmpB;\n\n    SAState() {\n        tmpA.reserve(256);\n        tmpB.reserve(256);\n        for (auto &v : lineIdx) v.reserve(256);\n    }\n\n    inline void getLineSeq(int lineId, uint8_t seq[N]) const {\n        if (lineId < 20) {\n            int r = lineId;\n            for (int c = 0; c < N; c++) seq[c] = (*mat)[r][c];\n        } else {\n            int c = lineId - 20;\n            for (int r = 0; r < N; r++) seq[r] = (*mat)[r][c];\n        }\n    }\n\n    inline void computeLineInto(int lineId, vector<int>& out) const {\n        out.clear();\n        uint8_t seq[N];\n        getLineSeq(lineId, seq);\n\n        const int minL = book->minLen;\n        const int maxL = book->maxLen;\n\n        for (int st = 0; st < N; st++) {\n            uint64_t bits = 0;\n            for (int l = 1; l <= maxL; l++) {\n                uint8_t v = seq[(st + l - 1) % N];\n                if (v == DOT) break;\n                bits = (bits << 3) | (uint64_t)v;\n                if (l >= minL) {\n                    uint64_t code = (uint64_t(l) << 36) | bits;\n                    auto it = book->code2idx.find(code);\n                    if (it != book->code2idx.end()) out.push_back(it->second);\n                }\n            }\n        }\n    }\n\n    inline void replaceSwapLine(int lineId, vector<int>& newVec) {\n        // remove old\n        for (int idx : lineIdx[lineId]) {\n            int &x = occ[idx];\n            x--;\n            if (x == 0) score -= book->weight[idx];\n        }\n        // add new\n        for (int idx : newVec) {\n            int &x = occ[idx];\n            if (x == 0) score += book->weight[idx];\n            x++;\n        }\n        lineIdx[lineId].swap(newVec); // now newVec holds old content (reusable for undo)\n    }\n\n    void init(array<array<uint8_t, N>, N> &m, const CodeBook& b) {\n        mat = &m;\n        book = &b;\n        occ.assign(book->codes.size(), 0);\n        score = 0;\n        for (int lineId = 0; lineId < 40; lineId++) {\n            vector<int> tmp;\n            tmp.reserve(256);\n            computeLineInto(lineId, tmp);\n            lineIdx[lineId] = std::move(tmp);\n            for (int idx : lineIdx[lineId]) {\n                int &x = occ[idx];\n                if (x == 0) score += book->weight[idx];\n                x++;\n            }\n        }\n        tmpA.clear(); tmpB.clear();\n        tmpA.reserve(256); tmpB.reserve(256);\n    }\n};\n\nstruct Solver {\n    int M;\n    vector<vector<uint8_t>> inputs;\n    RNG rng;\n    array<array<uint8_t, N>, N> mat;\n\n    explicit Solver(int M) : M(M) {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = RNG(seed);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = (uint8_t)rng.nextInt(0,7);\n    }\n\n    void anneal(SAState &st, double tStart, double tEnd, double T0, double T1,\n                bool allowImposeMove, double probShift, double probImpose) {\n        // SA until elapsed time reaches tEnd (seconds from global start)\n        while (true) {\n            double now = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (now >= tEnd) break;\n            double progress = (now - tStart) / max(1e-9, (tEnd - tStart));\n            progress = min(1.0, max(0.0, progress));\n            double T = T0 * pow(T1 / T0, progress);\n\n            double r = rng.nextDouble();\n\n            // phase2 impose move (helps when some full strings are still uncovered)\n            if (allowImposeMove && st.score < st.book->totalWeight && r < probImpose) {\n                // pick an uncovered code idx\n                int U = (int)st.occ.size();\n                int target = -1;\n                for (int tries = 0; tries < 30; tries++) {\n                    int idx = rng.nextInt(0, U - 1);\n                    if (st.occ[idx] == 0) { target = idx; break; }\n                }\n                if (target == -1) continue;\n\n                const auto &pat = st.book->pattern[target];\n                int k = (int)pat.size();\n                if (k < 2) continue;\n\n                // sample placements and pick one with minimal mismatches\n                bool bestVert = false;\n                int bestLine = 0, bestStart = 0;\n                int bestMismatch = 1e9;\n                const int trials = 60;\n                for (int tt = 0; tt < trials; tt++) {\n                    bool vert = (rng.nextInt(0,1) == 1);\n                    int line = rng.nextInt(0, N - 1);\n                    int start = rng.nextInt(0, N - 1);\n                    int mism = 0;\n                    if (!vert) {\n                        int row = line;\n                        for (int t = 0; t < k; t++) {\n                            int col = (start + t) % N;\n                            uint8_t cur = mat[row][col];\n                            if (cur != pat[t]) mism++;\n                        }\n                    } else {\n                        int col = line;\n                        for (int t = 0; t < k; t++) {\n                            int row = (start + t) % N;\n                            uint8_t cur = mat[row][col];\n                            if (cur != pat[t]) mism++;\n                        }\n                    }\n                    if (mism < bestMismatch) {\n                        bestMismatch = mism;\n                        bestVert = vert;\n                        bestLine = line;\n                        bestStart = start;\n                        if (bestMismatch == 0) break;\n                    }\n                }\n                if (bestMismatch == 0) continue; // should not happen if truly uncovered, but safe\n\n                // apply changes (store changed cells)\n                struct CellCh { int r,c; uint8_t oldv; };\n                vector<CellCh> changes;\n                changes.reserve(k);\n\n                vector<int> affectedLines;\n                affectedLines.reserve(40);\n                array<char, 40> aff = {};\n                auto markLine = [&](int id) {\n                    if (!aff[id]) { aff[id] = 1; affectedLines.push_back(id); }\n                };\n\n                if (!bestVert) {\n                    int row = bestLine;\n                    for (int t = 0; t < k; t++) {\n                        int col = (bestStart + t) % N;\n                        uint8_t nv = pat[t];\n                        if (mat[row][col] != nv) {\n                            changes.push_back({row, col, mat[row][col]});\n                            mat[row][col] = nv;\n                            markLine(row);\n                            markLine(20 + col);\n                        }\n                    }\n                } else {\n                    int col = bestLine;\n                    for (int t = 0; t < k; t++) {\n                        int row = (bestStart + t) % N;\n                        uint8_t nv = pat[t];\n                        if (mat[row][col] != nv) {\n                            changes.push_back({row, col, mat[row][col]});\n                            mat[row][col] = nv;\n                            markLine(row);\n                            markLine(20 + col);\n                        }\n                    }\n                }\n\n                // backup line vectors\n                vector<pair<int, vector<int>>> backups;\n                backups.reserve(affectedLines.size());\n                for (int lid : affectedLines) backups.push_back({lid, st.lineIdx[lid]});\n\n                long long oldScore = st.score;\n\n                // update lines\n                vector<int> tmp;\n                tmp.reserve(256);\n                for (int lid : affectedLines) {\n                    st.computeLineInto(lid, tmp);\n                    st.replaceSwapLine(lid, tmp);\n                }\n                long long delta = st.score - oldScore;\n\n                bool accept = false;\n                if (delta >= 0) accept = true;\n                else {\n                    double logu = log(max(1e-300, rng.nextDouble()));\n                    if (logu < (double)delta / T) accept = true;\n                }\n\n                if (!accept) {\n                    // restore lines\n                    for (auto &bk : backups) {\n                        int lid = bk.first;\n                        st.replaceSwapLine(lid, bk.second);\n                    }\n                    // restore cells\n                    for (auto &ch : changes) mat[ch.r][ch.c] = ch.oldv;\n                }\n                continue;\n            }\n\n            // row/col cyclic shift move\n            if (r < probShift) {\n                bool shiftRow = (rng.nextInt(0,1) == 0);\n                int id = rng.nextInt(0, N - 1);\n                int dir = (rng.nextInt(0,1) == 0 ? -1 : +1);\n\n                // backup cells\n                uint8_t buf[N];\n                if (shiftRow) {\n                    for (int c = 0; c < N; c++) buf[c] = mat[id][c];\n                    for (int c = 0; c < N; c++) {\n                        int src = (c - dir + N) % N;\n                        mat[id][c] = buf[src];\n                    }\n                } else {\n                    for (int r2 = 0; r2 < N; r2++) buf[r2] = mat[r2][id];\n                    for (int r2 = 0; r2 < N; r2++) {\n                        int src = (r2 - dir + N) % N;\n                        mat[r2][id] = buf[src];\n                    }\n                }\n\n                // affected lines: that row/col + all perpendicular lines\n                vector<int> affected;\n                affected.reserve(21);\n                if (shiftRow) {\n                    affected.push_back(id);\n                    for (int c = 0; c < N; c++) affected.push_back(20 + c);\n                } else {\n                    affected.push_back(20 + id);\n                    for (int r2 = 0; r2 < N; r2++) affected.push_back(r2);\n                }\n\n                vector<pair<int, vector<int>>> backups;\n                backups.reserve(affected.size());\n                for (int lid : affected) backups.push_back({lid, st.lineIdx[lid]});\n\n                long long oldScore = st.score;\n                vector<int> tmp;\n                tmp.reserve(256);\n                for (int lid : affected) {\n                    st.computeLineInto(lid, tmp);\n                    st.replaceSwapLine(lid, tmp);\n                }\n                long long delta = st.score - oldScore;\n\n                bool accept = false;\n                if (delta >= 0) accept = true;\n                else {\n                    double logu = log(max(1e-300, rng.nextDouble()));\n                    if (logu < (double)delta / T) accept = true;\n                }\n\n                if (!accept) {\n                    // restore lines\n                    for (auto &bk : backups) st.replaceSwapLine(bk.first, bk.second);\n                    // restore cells\n                    if (shiftRow) {\n                        for (int c = 0; c < N; c++) mat[id][c] = buf[c];\n                    } else {\n                        for (int r2 = 0; r2 < N; r2++) mat[r2][id] = buf[r2];\n                    }\n                }\n                continue;\n            }\n\n            // single cell change move\n            int i = rng.nextInt(0, N - 1);\n            int j = rng.nextInt(0, N - 1);\n            uint8_t oldv = mat[i][j];\n            uint8_t newv = oldv;\n            // do not generate DOT during SA; DOT is only for final pruning\n            while (newv == oldv) newv = (uint8_t)rng.nextInt(0, 7);\n\n            mat[i][j] = newv;\n\n            int rowLine = i;\n            int colLine = 20 + j;\n\n            long long oldScore = st.score;\n\n            st.computeLineInto(rowLine, st.tmpA);\n            st.computeLineInto(colLine, st.tmpB);\n\n            st.replaceSwapLine(rowLine, st.tmpA);\n            st.replaceSwapLine(colLine, st.tmpB);\n\n            long long delta = st.score - oldScore;\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double logu = log(max(1e-300, rng.nextDouble()));\n                if (logu < (double)delta / T) accept = true;\n            }\n\n            if (!accept) {\n                // undo: swap back lines and restore cell\n                st.replaceSwapLine(colLine, st.tmpB);\n                st.replaceSwapLine(rowLine, st.tmpA);\n                mat[i][j] = oldv;\n            }\n        }\n    }\n\n    chrono::steady_clock::time_point startTime;\n\n    void solveAndPrint() {\n        // Build weights for phase1: substrings length 3..6\n        FlatMap w1; w1.reserve((size_t)30000);\n        // Build weights for phase2: full strings\n        FlatMap w2; w2.reserve((size_t)2048);\n\n        // read/prepare inputs already in this->inputs\n        // phase1 factors\n        auto factor = [&](int len) -> int {\n            // len 3..6 -> 1,2,4,8\n            return 1 << (len - 3);\n        };\n\n        for (auto &s : inputs) {\n            // full string weight (duplicates handled by sum)\n            w2[encodeFull(s)] += 1;\n\n            int L = (int)s.size();\n            for (int len = 3; len <= 6; len++) {\n                if (len > L) break;\n                int f = factor(len);\n                for (int st = 0; st + len <= L; st++) {\n                    w1[encodeVec(s, st, len)] += f;\n                }\n            }\n        }\n\n        CodeBook book1 = makeCodeBook(w1, 3, 6, false);\n        CodeBook book2 = makeCodeBook(w2, 2, 12, true);\n\n        startTime = chrono::steady_clock::now();\n        double TL = 2.85; // safety\n\n        SAState st;\n\n        // Phase 1: proxy k-mer coverage\n        st.init(mat, book1);\n        double t0 = 0.0;\n        double t1 = 1.55; // seconds\n        anneal(st, t0, t1, /*T0*/ 2500.0, /*T1*/ 10.0, false, /*probShift*/ 0.03, /*probImpose*/ 0.0);\n\n        // Phase 2: true objective (cover all full strings)\n        st.init(mat, book2);\n        double t2 = t1;\n        double t3 = TL;\n        anneal(st, t2, t3, /*T0*/ 250.0, /*T1*/ 0.5, true, /*probShift*/ 0.02, /*probImpose*/ 0.08);\n\n        // If fully covered, try to increase '.' by removing cells greedily.\n        if (st.score == book2.totalWeight) {\n            vector<int> order(N * N);\n            iota(order.begin(), order.end(), 0);\n            // shuffle\n            for (int k = (int)order.size() - 1; k > 0; k--) {\n                int r = rng.nextInt(0, k);\n                swap(order[k], order[r]);\n            }\n\n            for (int p : order) {\n                int i = p / N, j = p % N;\n                if (mat[i][j] == DOT) continue;\n                uint8_t oldv = mat[i][j];\n                mat[i][j] = DOT;\n\n                int rowLine = i;\n                int colLine = 20 + j;\n\n                st.computeLineInto(rowLine, st.tmpA);\n                st.computeLineInto(colLine, st.tmpB);\n\n                long long oldScore = st.score;\n                st.replaceSwapLine(rowLine, st.tmpA);\n                st.replaceSwapLine(colLine, st.tmpB);\n\n                if (st.score != book2.totalWeight) {\n                    // undo\n                    st.replaceSwapLine(colLine, st.tmpB);\n                    st.replaceSwapLine(rowLine, st.tmpA);\n                    mat[i][j] = oldv;\n                }\n            }\n        }\n\n        // Output\n        for (int i = 0; i < N; i++) {\n            string out;\n            out.reserve(N);\n            for (int j = 0; j < N; j++) {\n                uint8_t v = mat[i][j];\n                if (v == DOT) out.push_back('.');\n                else out.push_back(char('A' + v));\n            }\n            cout << out << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, M;\n    cin >> n >> M;\n    Solver solver(M);\n    solver.inputs.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        string s;\n        cin >> s;\n        vector<uint8_t> v;\n        v.reserve(s.size());\n        for (char c : s) v.push_back((uint8_t)(c - 'A')); // 'A'..'H' -> 0..7\n        solver.inputs.push_back(std::move(v));\n    }\n\n    solver.solveAndPrint();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed=88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint64_t operator()() { return next(); }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, si, sj;\n    vector<string> c;\n\n    vector<vector<int>> id;     // -1 for obstacle\n    vector<int> xs, ys, w;      // per node id\n    int R = 0;\n\n    vector<int> hseg, vseg;\n    int H = 0, V = 0;\n\n    // For visibility bitsets\n    int W64 = 0;\n    vector<uint64_t> hbits, vbits;     // segment bitsets: size segCount * W64\n    vector<uint64_t> visFlat;          // per node: size R * W64\n    vector<uint64_t> allMask;          // required bits set\n\n    // Dijkstra buffers (reused)\n    vector<long long> dist;\n    vector<int> prevv;\n\n    static constexpr long long INF = (1LL<<60);\n\n    inline bool inb(int x,int y){ return 0<=x && x<N && 0<=y && y<N; }\n\n    void read() {\n        cin >> N >> si >> sj;\n        c.resize(N);\n        for(int i=0;i<N;i++) cin >> c[i];\n    }\n\n    void build_nodes() {\n        id.assign(N, vector<int>(N, -1));\n        xs.clear(); ys.clear(); w.clear();\n        for(int i=0;i<N;i++){\n            for(int j=0;j<N;j++){\n                if(c[i][j] == '#') continue;\n                id[i][j] = R++;\n                xs.push_back(i);\n                ys.push_back(j);\n                w.push_back(c[i][j]-'0');\n            }\n        }\n        dist.assign(R, INF);\n        prevv.assign(R, -1);\n        hseg.assign(R, -1);\n        vseg.assign(R, -1);\n    }\n\n    void build_segments() {\n        // Horizontal segments\n        H = 0;\n        for(int i=0;i<N;i++){\n            int j=0;\n            while(j<N){\n                if(id[i][j] == -1){ j++; continue; }\n                int segId = H++;\n                while(j<N && id[i][j] != -1){\n                    hseg[id[i][j]] = segId;\n                    j++;\n                }\n            }\n        }\n        // Vertical segments\n        V = 0;\n        for(int j=0;j<N;j++){\n            int i=0;\n            while(i<N){\n                if(id[i][j] == -1){ i++; continue; }\n                int segId = V++;\n                while(i<N && id[i][j] != -1){\n                    vseg[id[i][j]] = segId;\n                    i++;\n                }\n            }\n        }\n    }\n\n    void build_visibility_bitsets() {\n        W64 = (R + 63) / 64;\n        hbits.assign((size_t)H * W64, 0ULL);\n        vbits.assign((size_t)V * W64, 0ULL);\n        visFlat.assign((size_t)R * W64, 0ULL);\n\n        // Fill segment bitsets\n        for(int v=0; v<R; v++){\n            int hi = hseg[v], vi = vseg[v];\n            int word = v >> 6;\n            int bit = v & 63;\n            hbits[(size_t)hi * W64 + word] |= (1ULL << bit);\n            vbits[(size_t)vi * W64 + word] |= (1ULL << bit);\n        }\n\n        // For each node: union of its horizontal and vertical segments\n        for(int v=0; v<R; v++){\n            uint64_t* dst = &visFlat[(size_t)v * W64];\n            const uint64_t* hb = &hbits[(size_t)hseg[v] * W64];\n            const uint64_t* vb = &vbits[(size_t)vseg[v] * W64];\n            for(int k=0;k<W64;k++) dst[k] = hb[k] | vb[k];\n        }\n\n        // allMask\n        allMask.assign(W64, ~0ULL);\n        if(R % 64 != 0){\n            allMask[W64-1] = (1ULL << (R%64)) - 1ULL;\n        }\n    }\n\n    inline void for_neighbors(int v, const function<void(int)>& f) const {\n        int x = xs[v], y = ys[v];\n        // UDLR\n        if(x>0){\n            int u=id[x-1][y];\n            if(u!=-1) f(u);\n        }\n        if(x+1<N){\n            int u=id[x+1][y];\n            if(u!=-1) f(u);\n        }\n        if(y>0){\n            int u=id[x][y-1];\n            if(u!=-1) f(u);\n        }\n        if(y+1<N){\n            int u=id[x][y+1];\n            if(u!=-1) f(u);\n        }\n    }\n\n    // Dijkstra until predicate true when node is popped (shortest confirmed), return that node.\n    template<class Pred>\n    int dijkstra_until(int s, Pred pred) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            if(pred(v)) return v;\n            for_neighbors(v, [&](int to){\n                long long nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push({nd,to});\n                }\n            });\n        }\n        return -1; // should not happen in connected component\n    }\n\n    vector<int> restore_path(int s, int t) {\n        vector<int> path;\n        int cur = t;\n        while(cur != -1){\n            path.push_back(cur);\n            if(cur == s) break;\n            cur = prevv[cur];\n        }\n        reverse(path.begin(), path.end());\n        // If not connected, path[0] wouldn't be s; but should not happen.\n        return path;\n    }\n\n    long long route_time(const vector<int>& route) const {\n        long long t = 0;\n        for(size_t i=1;i<route.size();i++) t += w[route[i]];\n        return t;\n    }\n\n    // Segment coverage evaluation (fast)\n    pair<bool,long long> eval_segments(const vector<int>& route, const vector<int>& segOf, int S) const {\n        vector<char> seen(S, 0);\n        int cnt = 0;\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            int s = segOf[v];\n            if(!seen[s]){\n                seen[s] = 1;\n                if(++cnt == S) {\n                    // still continue for time? we already computed along the way\n                }\n            }\n        }\n        return {cnt == S, t};\n    }\n\n    // True full visibility evaluation via bitsets (slower)\n    pair<bool,long long> eval_full_visibility(const vector<int>& route) const {\n        vector<uint64_t> cov(W64, 0ULL);\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            const uint64_t* vb = &visFlat[(size_t)v * W64];\n            for(int k=0;k<W64;k++) cov[k] |= vb[k];\n        }\n        for(int k=0;k<W64;k++){\n            if(cov[k] != allMask[k]) return {false, t};\n        }\n        return {true, t};\n    }\n\n    // Greedy route: repeatedly go to nearest uncovered segment (multi-target Dijkstra)\n    vector<int> build_route_covering_segments(const vector<int>& segOf, int S, int startId) {\n        vector<char> covered(S, 0);\n        int coveredCnt = 0;\n        auto cover_node = [&](int v){\n            int s = segOf[v];\n            if(!covered[s]){\n                covered[s] = 1;\n                coveredCnt++;\n            }\n        };\n\n        vector<int> route;\n        route.push_back(startId);\n        cover_node(startId);\n        int cur = startId;\n\n        while(coveredCnt < S){\n            int target = dijkstra_until(cur, [&](int v){\n                return !covered[segOf[v]];\n            });\n            if(target == -1) break;\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++){\n                route.push_back(path[i]);\n                cover_node(path[i]);\n            }\n            cur = target;\n        }\n\n        // return to start\n        if(cur != startId){\n            int target = dijkstra_until(cur, [&](int v){ return v == startId; });\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++) route.push_back(path[i]);\n        }\n\n        // Avoid t=0 corner: add a tiny cycle if possible and route has no moves\n        if(route.size() == 1 && R > 1){\n            int s = startId;\n            int nb = -1;\n            for_neighbors(s, [&](int to){ if(nb==-1) nb=to; });\n            if(nb != -1){\n                route.push_back(nb);\n                route.push_back(s);\n            }\n        }\n        return route;\n    }\n\n    vector<int> improve_by_shortcuts_segments(vector<int> route, const vector<int>& segOf, int S,\n                                             double timeLimitSec, XorShift64& rng) {\n        auto startTime = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_segments(route, segOf, S);\n        (void)ok0;\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 8) continue;\n\n            int len = 5 + (int)(rng() % 200);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            // prefix cost for old subpath\n            // oldCost: cost to go from route[a] to route[b] following current route\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> newRoute;\n            newRoute.reserve(route.size() - (b - a + 1) + path.size());\n            newRoute.insert(newRoute.end(), route.begin(), route.begin() + a);\n            newRoute.insert(newRoute.end(), path.begin(), path.end());\n            newRoute.insert(newRoute.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_segments(newRoute, segOf, S);\n            if(ok && newT < bestT){\n                route.swap(newRoute);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    vector<int> improve_by_shortcuts_full(vector<int> route, double timeLimitSec, XorShift64& rng) {\n        auto startTime = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_full_visibility(route);\n        if(!ok0) {\n            // Shouldn't happen; keep route as-is.\n            return route;\n        }\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 8) continue;\n\n            int len = 5 + (int)(rng() % 180);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> newRoute;\n            newRoute.reserve(route.size() - (b - a + 1) + path.size());\n            newRoute.insert(newRoute.end(), route.begin(), route.begin() + a);\n            newRoute.insert(newRoute.end(), path.begin(), path.end());\n            newRoute.insert(newRoute.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_full_visibility(newRoute);\n            if(ok && newT < bestT){\n                route.swap(newRoute);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    string route_to_moves(const vector<int>& route) const {\n        string out;\n        out.reserve(route.size() ? route.size()-1 : 0);\n        for(size_t i=1;i<route.size();i++){\n            int a = route[i-1], b = route[i];\n            int x1=xs[a], y1=ys[a], x2=xs[b], y2=ys[b];\n            if(x2==x1-1 && y2==y1) out.push_back('U');\n            else if(x2==x1+1 && y2==y1) out.push_back('D');\n            else if(x2==x1 && y2==y1-1) out.push_back('L');\n            else if(x2==x1 && y2==y1+1) out.push_back('R');\n            else {\n                // Should not happen; fallback (but would be illegal)\n                // Keep empty.\n            }\n        }\n        return out;\n    }\n\n    void solve() {\n        read();\n        build_nodes();\n        build_segments();\n        build_visibility_bitsets();\n\n        int startId = id[si][sj];\n\n        // Build both orientation routes (cover all segments in that orientation)\n        vector<int> segH = hseg;\n        vector<int> segV = vseg;\n\n        XorShift64 rng;\n\n        vector<int> routeH = build_route_covering_segments(segH, H, startId);\n        vector<int> routeV = build_route_covering_segments(segV, V, startId);\n\n        // Choose better by actual travel time\n        long long tH = route_time(routeH);\n        long long tV = route_time(routeV);\n\n        vector<int> route;\n        vector<int> segOf;\n        int S;\n        if(tH <= tV){\n            route = std::move(routeH);\n            segOf = std::move(segH);\n            S = H;\n        }else{\n            route = std::move(routeV);\n            segOf = std::move(segV);\n            S = V;\n        }\n\n        // Total time budget ~3 sec; keep some margin\n        auto globalStart = chrono::steady_clock::now();\n\n        // Phase 1: segment-preserving shortcut improvements (fast checks)\n        route = improve_by_shortcuts_segments(std::move(route), segOf, S, 1.4, rng);\n\n        // Phase 2: true-visibility shortcut improvements (expensive checks, fewer iterations)\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalStart).count();\n        double remain = 2.85 - elapsed;\n        if(remain > 0.05){\n            route = improve_by_shortcuts_full(std::move(route), remain, rng);\n        }\n\n        // Output\n        cout << route_to_moves(route) << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    s.solve();\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Item {\n    long long key;\n    int id;\n};\nstruct ItemCmp {\n    bool operator()(const Item& a, const Item& b) const {\n        return a.key < b.key; // max-heap by key\n    }\n};\n\nstatic inline double clampd(double x, double lo, double hi) {\n    if (x < lo) return lo;\n    if (x > hi) return hi;\n    return x;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    vector<vector<int>> d(N, vector<int>(K));\n    for (int i = 0; i < N; i++) {\n        for (int k = 0; k < K; k++) cin >> d[i][k];\n    }\n\n    vector<vector<int>> g(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        g[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    // Critical path length cp[i] (reverse topological by index works since u<v always).\n    vector<int> cp(N, 1);\n    for (int i = N - 1; i >= 0; i--) {\n        int best = 1;\n        for (int v : g[i]) best = max(best, 1 + cp[v]);\n        cp[i] = best;\n    }\n\n    // Difficulty: sum of required levels (cheap proxy for duration).\n    vector<int> diff(N, 0);\n    for (int i = 0; i < N; i++) {\n        int s = 0;\n        for (int k = 0; k < K; k++) s += d[i][k];\n        diff[i] = s;\n    }\n\n    // Static priority key: criticality dominates, then difficulty, then outdegree, then smaller index slightly.\n    vector<long long> key(N);\n    for (int i = 0; i < N; i++) {\n        key[i] = (long long)cp[i] * 1'000'000LL\n               + (long long)diff[i] * 1'000LL\n               + (long long)outdeg[i] * 10LL\n               - (long long)i;\n    }\n\n    // Task states: 0=not started, 1=in progress, 2=done\n    vector<int> state(N, 0);\n\n    priority_queue<Item, vector<Item>, ItemCmp> pq;\n    for (int i = 0; i < N; i++) {\n        if (indeg[i] == 0) pq.push({key[i], i});\n    }\n\n    // Skill estimates\n    const double SKILL_INIT = 20.0; // start modestly to avoid \"everything predicted as 1 day\"\n    const double SKILL_MIN = 0.0;\n    const double SKILL_MAX = 80.0;\n\n    vector<vector<double>> shat(M, vector<double>(K, SKILL_INIT));\n    vector<int> samples(M, 0);\n\n    // Member state\n    vector<int> member_task(M, -1);\n    vector<int> member_start(M, -1);\n\n    auto predict_time = [&](int task, int mem) -> double {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double def = (double)d[task][k] - shat[mem][k];\n            if (def > 0) w += def;\n        }\n        if (w <= 1e-9) return 1.0;\n        return max(1.0, w);\n    };\n\n    auto update_skill = [&](int mem, int task, int t_obs) {\n        // target deficit\n        double w_target = (t_obs <= 1 ? 0.0 : (double)t_obs);\n\n        double w_hat = 0.0;\n        vector<int> active;\n        active.reserve(K);\n        for (int k = 0; k < K; k++) {\n            double def = (double)d[task][k] - shat[mem][k];\n            if (def > 0) {\n                w_hat += def;\n                active.push_back(k);\n            }\n        }\n\n        double err = w_hat - w_target;\n        if (fabs(err) < 0.5) return; // ignore tiny noise\n\n        if (active.empty()) {\n            // If we predicted w=0 but took >1 days, we must lower some skills.\n            // Spread over all dimensions (small step anyway).\n            for (int k = 0; k < K; k++) active.push_back(k);\n        }\n\n        double lr = 0.6 / sqrt(1.0 + samples[mem]); // decreasing step size\n        double delta = lr * err / (double)active.size();\n        delta = clampd(delta, -4.0, 4.0);\n\n        for (int k : active) {\n            shat[mem][k] = clampd(shat[mem][k] + delta, SKILL_MIN, SKILL_MAX);\n        }\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const int L = 300; // number of candidate ready tasks to consider each day\n\n    for (int day = 1; day <= 2000; day++) {\n        // Collect free members\n        vector<int> free_members;\n        free_members.reserve(M);\n        for (int j = 0; j < M; j++) if (member_task[j] == -1) free_members.push_back(j);\n        shuffle(free_members.begin(), free_members.end(), rng);\n\n        // Extract top-L candidates from pq (skipping stale entries)\n        vector<int> cand;\n        cand.reserve(L);\n        while (!pq.empty() && (int)cand.size() < L) {\n            auto it = pq.top(); pq.pop();\n            int t = it.id;\n            if (state[t] != 0) continue;\n            if (indeg[t] != 0) continue; // not ready anymore (shouldn't happen, but safe)\n            cand.push_back(t);\n        }\n\n        // cand is already roughly in descending key order due to pq, but keep it explicit:\n        sort(cand.begin(), cand.end(), [&](int a, int b){\n            if (key[a] != key[b]) return key[a] > key[b];\n            return a < b;\n        });\n\n        vector<pair<int,int>> assigns; // (member, task)\n        vector<char> used(cand.size(), 0);\n\n        // Greedy: iterate tasks by priority, assign best free member.\n        for (int idx = 0; idx < (int)cand.size(); idx++) {\n            if (free_members.empty()) break;\n            int task = cand[idx];\n\n            int best_m = -1;\n            double best_cost = 1e100;\n\n            for (int mi = 0; mi < (int)free_members.size(); mi++) {\n                int mem = free_members[mi];\n                double pt = predict_time(task, mem);\n\n                // Tie-breaking/soft exploration: prefer members with fewer samples if similar.\n                // This is a tiny bias; main driver is predicted time.\n                double cost = pt - 0.02 / (1.0 + samples[mem]);\n\n                if (cost < best_cost) {\n                    best_cost = cost;\n                    best_m = mem;\n                }\n            }\n\n            // Assign\n            assigns.push_back({best_m, task});\n            used[idx] = 1;\n\n            state[task] = 1;\n            member_task[best_m] = task;\n            member_start[best_m] = day;\n\n            // remove member from free_members\n            for (int mi = 0; mi < (int)free_members.size(); mi++) {\n                if (free_members[mi] == best_m) {\n                    free_members[mi] = free_members.back();\n                    free_members.pop_back();\n                    break;\n                }\n            }\n        }\n\n        // Push back unused candidates\n        for (int idx = 0; idx < (int)cand.size(); idx++) {\n            if (!used[idx]) {\n                int t = cand[idx];\n                if (state[t] == 0 && indeg[t] == 0) pq.push({key[t], t});\n            }\n        }\n\n        // Output\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) {\n            cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        }\n        cout << '\\n' << flush;\n\n        // Input: finished members\n        int nfin;\n        cin >> nfin;\n        if (nfin == -1) return 0;\n\n        for (int x = 0; x < nfin; x++) {\n            int f;\n            cin >> f;\n            --f;\n            int task = member_task[f];\n            int st = member_start[f];\n            int t_obs = day - st + 1;\n\n            // Update skill estimate\n            update_skill(f, task, t_obs);\n            samples[f]++;\n\n            // Mark completed\n            member_task[f] = -1;\n            member_start[f] = -1;\n\n            state[task] = 2;\n            for (int v : g[task]) {\n                indeg[v]--;\n                if (indeg[v] == 0 && state[v] == 0) {\n                    pq.push({key[v], v});\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Order {\n    int ax, ay, cx, cy;\n};\n\nstruct Point {\n    int x, y;\n};\n\nstatic inline int manhattan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nstruct Node {\n    int id;      // 0..999\n    uint8_t tp;  // 0 = pickup, 1 = delivery\n};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n\n    static inline uint64_t splitmix64(uint64_t &s) {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline uint64_t next_u64() { return splitmix64(x); }\n    inline uint32_t next_u32() { return (uint32_t)next_u64(); }\n\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n\n    inline double next_double() { // [0,1)\n        // 53-bit precision\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic const Point OFFICE{400, 400};\n\nstruct State {\n    vector<int> sel;             // size 50\n    array<Node, 100> seq;        // size 100\n    int cost = INT_MAX;\n};\n\nstatic inline Point nodePoint(const vector<Order>& ord, const Node& nd) {\n    const auto &o = ord[nd.id];\n    if (nd.tp == 0) return Point{o.ax, o.ay};\n    else return Point{o.cx, o.cy};\n}\n\nstatic int computeCost(const vector<Order>& ord, const array<Node,100>& seq) {\n    int c = 0;\n    Point cur = OFFICE;\n    for (int i = 0; i < 100; i++) {\n        Point nxt = nodePoint(ord, seq[i]);\n        c += manhattan(cur, nxt);\n        cur = nxt;\n    }\n    c += manhattan(cur, OFFICE);\n    return c;\n}\n\nstatic bool checkOrderValid(const array<Node,100>& seq, int id) {\n    int p = -1, d = -1;\n    for (int i = 0; i < 100; i++) {\n        if (seq[i].id == id) {\n            if (seq[i].tp == 0) p = i;\n            else d = i;\n        }\n    }\n    return (p != -1 && d != -1 && p < d);\n}\n\n// Greedy interleaving constructor: always feasible.\nstatic array<Node,100> buildGreedyInterleaving(const vector<Order>& ord, const vector<int>& sel) {\n    vector<int> unpicked = sel;\n    vector<int> carrying;\n    carrying.reserve(50);\n\n    array<Node,100> seq;\n    Point cur = OFFICE;\n\n    auto erase_by_swap_back = [](vector<int>& v, int idx) {\n        v[idx] = v.back();\n        v.pop_back();\n    };\n\n    for (int t = 0; t < 100; t++) {\n        int bestDist = INT_MAX;\n        int bestId = -1;\n        int bestType = -1; // 0 pickup, 1 delivery\n        int bestIdx = -1;  // index in unpicked/carrying\n\n        // Try pickups\n        for (int i = 0; i < (int)unpicked.size(); i++) {\n            int id = unpicked[i];\n            Point p{ord[id].ax, ord[id].ay};\n            int d = manhattan(cur, p);\n            if (d < bestDist) {\n                bestDist = d;\n                bestId = id;\n                bestType = 0;\n                bestIdx = i;\n            }\n        }\n        // Try deliveries\n        for (int i = 0; i < (int)carrying.size(); i++) {\n            int id = carrying[i];\n            Point p{ord[id].cx, ord[id].cy};\n            int d = manhattan(cur, p);\n            if (d < bestDist) {\n                bestDist = d;\n                bestId = id;\n                bestType = 1;\n                bestIdx = i;\n            }\n        }\n\n        if (bestType == 0) {\n            seq[t] = Node{bestId, 0};\n            cur = Point{ord[bestId].ax, ord[bestId].ay};\n            carrying.push_back(bestId);\n            erase_by_swap_back(unpicked, bestIdx);\n        } else {\n            seq[t] = Node{bestId, 1};\n            cur = Point{ord[bestId].cx, ord[bestId].cy};\n            erase_by_swap_back(carrying, bestIdx);\n        }\n    }\n    return seq;\n}\n\nstatic inline bool inSelLinear(const vector<int>& sel, int id) {\n    for (int x : sel) if (x == id) return true;\n    return false;\n}\n\n// Relocate element at i to position j (0..99) in array.\nstatic inline void applyRelocate(array<Node,100>& a, int i, int j) {\n    if (i == j) return;\n    Node tmp = a[i];\n    if (i < j) {\n        for (int k = i; k < j; k++) a[k] = a[k+1];\n        a[j] = tmp;\n    } else {\n        for (int k = i; k > j; k--) a[k] = a[k-1];\n        a[j] = tmp;\n    }\n}\n\nstatic void greedyImprove(const vector<Order>& ord, State& st, RNG& rng, int iters) {\n    for (int it = 0; it < iters; it++) {\n        array<Node,100> bak = st.seq;\n\n        // Relocate move (greedy)\n        int i = rng.next_int(0, 99);\n        int j = rng.next_int(0, 99);\n        if (i == j) continue;\n\n        int movedId = st.seq[i].id;\n        applyRelocate(st.seq, i, j);\n        if (!checkOrderValid(st.seq, movedId)) {\n            st.seq = bak;\n            continue;\n        }\n\n        int newCost = computeCost(ord, st.seq);\n        if (newCost < st.cost) {\n            st.cost = newCost;\n        } else {\n            st.seq = bak;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> ord(1000);\n    for (int i = 0; i < 1000; i++) {\n        cin >> ord[i].ax >> ord[i].ay >> ord[i].cx >> ord[i].cy;\n    }\n\n    // Candidate pool by solo cost\n    vector<pair<int,int>> solo; solo.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        Point p{ord[i].ax, ord[i].ay};\n        Point d{ord[i].cx, ord[i].cy};\n        int c = manhattan(OFFICE, p) + manhattan(p, d) + manhattan(d, OFFICE);\n        solo.push_back({c, i});\n    }\n    sort(solo.begin(), solo.end());\n\n    int POOL = 400;\n    vector<int> pool;\n    for (int i = 0; i < min(POOL, 1000); i++) pool.push_back(solo[i].second);\n\n    // RNG seed\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    RNG rng(seed);\n\n    // Initial selection: best 50 by solo cost\n    State cur, best;\n    cur.sel.resize(50);\n    for (int i = 0; i < 50; i++) cur.sel[i] = solo[i].second;\n\n    cur.seq = buildGreedyInterleaving(ord, cur.sel);\n    cur.cost = computeCost(ord, cur.seq);\n    greedyImprove(ord, cur, rng, 4000);\n    best = cur;\n\n    // Simulated annealing\n    const double TL = 1.95; // seconds\n    auto t0 = chrono::high_resolution_clock::now();\n\n    auto elapsedSec = [&]() -> double {\n        auto t1 = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(t1 - t0).count();\n    };\n\n    const double T0 = 3500.0;\n    const double T1 = 80.0;\n\n    int iter = 0;\n    while (true) {\n        double e = elapsedSec();\n        if (e >= TL) break;\n        double prog = e / TL;\n        double temp = T0 * pow(T1 / T0, prog);\n\n        double r = rng.next_double();\n\n        if (r < 0.965) {\n            // Relocate move\n            array<Node,100> bak = cur.seq;\n\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n\n            int movedId = cur.seq[i].id;\n            applyRelocate(cur.seq, i, j);\n            if (!checkOrderValid(cur.seq, movedId)) {\n                cur.seq = bak;\n                continue;\n            }\n\n            int newCost = computeCost(ord, cur.seq);\n            int delta = newCost - cur.cost;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(- (double)delta / temp);\n                accept = (rng.next_double() < prob);\n            }\n\n            if (accept) {\n                cur.cost = newCost;\n                if (cur.cost < best.cost) best = cur;\n            } else {\n                cur.seq = bak;\n            }\n        } else if (r < 0.99) {\n            // Swap two nodes (may violate precedence; check affected ids)\n            array<Node,100> bak = cur.seq;\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n\n            int id1 = cur.seq[i].id;\n            int id2 = cur.seq[j].id;\n\n            swap(cur.seq[i], cur.seq[j]);\n\n            // Only these orders can become invalid\n            if (!checkOrderValid(cur.seq, id1) || !checkOrderValid(cur.seq, id2)) {\n                cur.seq = bak;\n                continue;\n            }\n\n            int newCost = computeCost(ord, cur.seq);\n            int delta = newCost - cur.cost;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(- (double)delta / temp);\n                accept = (rng.next_double() < prob);\n            }\n\n            if (accept) {\n                cur.cost = newCost;\n                if (cur.cost < best.cost) best = cur;\n            } else {\n                cur.seq = bak;\n            }\n        } else {\n            // Selection swap (rare): replace one order with one from pool, rebuild route\n            State nxt = cur;\n\n            int outPos = rng.next_int(0, 49);\n            int outId = nxt.sel[outPos];\n\n            int inId = -1;\n            for (int tries = 0; tries < 50; tries++) {\n                int cand = pool[rng.next_int(0, (int)pool.size() - 1)];\n                if (!inSelLinear(nxt.sel, cand)) { inId = cand; break; }\n            }\n            if (inId == -1) continue;\n\n            nxt.sel[outPos] = inId;\n\n            // Rebuild route and do a small greedy improvement\n            nxt.seq = buildGreedyInterleaving(ord, nxt.sel);\n            nxt.cost = computeCost(ord, nxt.seq);\n            greedyImprove(ord, nxt, rng, 800);\n\n            int delta = nxt.cost - cur.cost;\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(- (double)delta / temp);\n                accept = (rng.next_double() < prob);\n            }\n            if (accept) {\n                cur = nxt;\n                if (cur.cost < best.cost) best = cur;\n            }\n        }\n\n        iter++;\n    }\n\n    // Output best\n    cout << 50;\n    for (int i = 0; i < 50; i++) cout << \" \" << (best.sel[i] + 1);\n    cout << \"\\n\";\n\n    // Build path points: OFFICE -> seq points -> OFFICE, compress consecutive duplicates\n    vector<Point> path;\n    path.reserve(102);\n    path.push_back(OFFICE);\n    for (int i = 0; i < 100; i++) path.push_back(nodePoint(ord, best.seq[i]));\n    path.push_back(OFFICE);\n\n    vector<Point> comp;\n    comp.reserve(path.size());\n    for (auto &p : path) {\n        if (comp.empty() || comp.back().x != p.x || comp.back().y != p.y) comp.push_back(p);\n    }\n\n    cout << (int)comp.size();\n    for (auto &p : comp) cout << \" \" << p.x << \" \" << p.y;\n    cout << \"\\n\";\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <atcoder/all>\n\nusing namespace std;\nusing atcoder::dsu;\n\n// ---------- HLD for max on path (edge values stored on child node positions) ----------\nstruct HLD {\n    int n;\n    vector<vector<pair<int,int>>> g; // to, edgeIndexInMSTAdj(not needed) ; we'll store edge id separately elsewhere\n    vector<int> parent, depth, heavy, head, pos, sz;\n    vector<int> parEdgeD; // d of edge to parent (root=0)\n    vector<int> parEdgeIdx; // original input index of edge to parent (root=-1)\n    int cur;\n\n    HLD(int n=0): n(n) {}\n\n    void build_from_tree(const vector<vector<tuple<int,int,int>>>& tree, int root=0) {\n        // tree[v]: (to, d, inputEdgeIndex)\n        n = (int)tree.size();\n        g.assign(n, {});\n        // We'll keep full info in temporary adjacency\n        // We'll do DFS with that adjacency; no need to fill g.\n        parent.assign(n, -1);\n        depth.assign(n, 0);\n        heavy.assign(n, -1);\n        head.assign(n, 0);\n        pos.assign(n, 0);\n        sz.assign(n, 0);\n        parEdgeD.assign(n, 0);\n        parEdgeIdx.assign(n, -1);\n\n        // Rooting DFS to set parent/depth/parEdge*\n        vector<int> st = {root};\n        parent[root] = -1;\n        depth[root] = 0;\n        vector<int> order;\n        order.reserve(n);\n        while(!st.empty()){\n            int v = st.back(); st.pop_back();\n            order.push_back(v);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                parent[to] = v;\n                depth[to] = depth[v] + 1;\n                parEdgeD[to] = d;\n                parEdgeIdx[to] = idx;\n                st.push_back(to);\n            }\n        }\n        // compute sizes and heavy in reverse order\n        for (int i = (int)order.size()-1; i>=0; --i) {\n            int v = order[i];\n            sz[v] = 1;\n            int bestSize = 0;\n            int bestChild = -1;\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                sz[v] += sz[to];\n                if (sz[to] > bestSize) {\n                    bestSize = sz[to];\n                    bestChild = to;\n                }\n            }\n            heavy[v] = bestChild;\n        }\n\n        // decompose\n        cur = 0;\n        function<void(int,int)> decomp = [&](int v, int h) {\n            head[v] = h;\n            pos[v] = cur++;\n            if (heavy[v] != -1) decomp(heavy[v], h);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v] || to == heavy[v]) continue;\n                decomp(to, to);\n            }\n        };\n        decomp(root, root);\n    }\n\n    template<class Seg>\n    int query_max(int a, int b, Seg &seg) const {\n        int res = 0;\n        int u=a, v=b;\n        while (head[u] != head[v]) {\n            if (depth[head[u]] < depth[head[v]]) swap(u, v);\n            // include head[u] position (its edge to parent is part of path except when head is root; root has 0)\n            res = max(res, seg.prod(pos[head[u]], pos[u] + 1));\n            u = parent[head[u]];\n        }\n        if (depth[u] > depth[v]) swap(u, v);\n        // u is LCA; exclude pos[u] (edge to parent of LCA not on path)\n        res = max(res, seg.prod(pos[u] + 1, pos[v] + 1));\n        return res;\n    }\n};\n\n// segtree for max<int>\nint op_max(int a, int b){ return max(a,b); }\nint e_max(){ return 0; }\n\n// ---------- main ----------\nstatic inline int rounded_dist(int x1,int y1,int x2,int y2){\n    long long dx = x1 - x2;\n    long long dy = y1 - y2;\n    double dist = std::sqrt((double)dx*dx + (double)dy*dy);\n    return (int)llround(dist);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 400;\n    const int M = 1995;\n\n    vector<int> x(N), y(N);\n    for(int i=0;i<N;i++){\n        if(!(cin >> x[i] >> y[i])) return 0;\n    }\n    vector<int> U(M), V(M);\n    for(int i=0;i<M;i++){\n        cin >> U[i] >> V[i];\n    }\n\n    vector<int> D(M);\n    for(int i=0;i<M;i++){\n        D[i] = rounded_dist(x[U[i]], y[U[i]], x[V[i]], y[V[i]]);\n        if (D[i] < 0) D[i] = 0;\n    }\n\n    // Build MST on given edges using weight D[i] (guidance only)\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        if (D[a] != D[b]) return D[a] < D[b];\n        if (U[a] != U[b]) return U[a] < U[b];\n        if (V[a] != V[b]) return V[a] < V[b];\n        return a < b;\n    });\n\n    dsu dsu_mst(N);\n    vector<char> inMST(M, false);\n    vector<vector<tuple<int,int,int>>> tree(N); // to, d, inputIndex\n    int picked = 0;\n    for(int idx: ord){\n        if (picked == N-1) break;\n        int u=U[idx], v=V[idx];\n        if(dsu_mst.same(u,v)) continue;\n        dsu_mst.merge(u,v);\n        inMST[idx]=true;\n        picked++;\n        tree[u].push_back({v, D[idx], idx});\n        tree[v].push_back({u, D[idx], idx});\n    }\n    // (Graph guaranteed connected, so picked==N-1)\n\n    // Build HLD + segtree on this MST\n    HLD hld;\n    hld.build_from_tree(tree, 0);\n\n    // map input edge index -> child node in rooted MST (for updates)\n    vector<int> idxToChild(M, -1);\n    for(int v=1; v<N; v++){\n        int idx = hld.parEdgeIdx[v];\n        if(idx >= 0) idxToChild[idx] = v;\n    }\n\n    vector<int> init(N, 0);\n    for(int v=1; v<N; v++){\n        init[hld.pos[v]] = hld.parEdgeD[v]; // edge value on child position\n    }\n    atcoder::segtree<int, op_max, e_max> seg(init);\n\n    // Adopted forest DSU\n    dsu dsu_acc(N);\n    vector<pair<int,int>> adopted;\n    adopted.reserve(N-1);\n    int comps = N;\n\n    auto can_reject = [&](int i)->bool{\n        dsu tmp(N);\n        for(auto &e: adopted) tmp.merge(e.first, e.second);\n        for(int j=i+1;j<M;j++){\n            tmp.merge(U[j], V[j]);\n        }\n        return tmp.size(0) == N;\n    };\n\n    for(int i=0;i<M;i++){\n        int l;\n        if(!(cin >> l)) break;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        if (comps == 1) {\n            ans = 0;\n        } else if (dsu_acc.same(u,v)) {\n            ans = 0; // never take cycle edges\n        } else {\n            bool okReject = can_reject(i);\n            bool take = false;\n\n            if (!okReject) {\n                take = true; // forced (bridge in remaining available graph)\n            } else {\n                // dynamic thresholds (mildly relaxed near the end / when urgent)\n                double t = (M <= 1) ? 1.0 : (double)i / (double)(M-1);\n                double remain = max(1, (M-1-i));\n                double need = comps - 1;\n                double urg = need / remain;           // ~0..>1 (cap below)\n                double mult = 1.0 + 0.8 * min(1.0, urg);\n\n                auto cap3 = [&](double r){ return min(3.0, r); };\n                int cheapR = (int)llround(cap3((1.35 + 0.35*t) * mult) * 1000.0);  // vs D[i]\n                int replR  = (int)llround(cap3((1.75 + 0.35*t) * mult) * 1000.0);  // vs md\n                int treeR  = (int)llround(cap3((2.10 + 0.30*t) * mult) * 1000.0);  // MST edges slightly looser\n\n                long long L = l;\n                long long di = D[i];\n\n                // If it's an MST edge and not too bad, often keep it.\n                if (inMST[i] && L*1000LL <= di * (long long)treeR) take = true;\n\n                // Very cheap by its own distance\n                if (!take && L*1000LL <= di * (long long)cheapR) take = true;\n\n                // Competitive compared to remaining MST bottleneck on u-v path\n                if (!take) {\n                    int md = hld.query_max(u, v, seg); // max remaining D on MST path\n                    if (md > 0) {\n                        // require di not much larger than md (di <= 1.25*md)\n                        if (di*1000LL <= (long long)md * 1250LL &&\n                            L*1000LL <= (long long)md * (long long)replR) {\n                            take = true;\n                        }\n                    }\n                }\n            }\n\n            if (take) {\n                dsu_acc.merge(u,v);\n                adopted.push_back({u,v});\n                comps--;\n                ans = 1;\n            } else {\n                ans = 0;\n            }\n        }\n\n        cout << ans << \"\\n\";\n        cout.flush();\n\n        // Remove MST edge from \"future MST edges\" structure once its index is processed\n        if (inMST[i]) {\n            int child = idxToChild[i];\n            if (child != -1) seg.set(hld.pos[child], 0);\n        }\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 30, W = 30;\nstatic constexpr int INF = 1e9;\n\nstruct Pet {\n    int x, y, t;\n};\nstruct Human {\n    int x, y;\n};\n\nstruct Rect {\n    int x1, x2, y1, y2; // inclusive\n};\n\nstatic inline bool inb(int x, int y) { return 1 <= x && x <= H && 1 <= y && y <= W; }\n\nstatic const int dx4[4] = {-1, +1, 0, 0};\nstatic const int dy4[4] = {0, 0, -1, +1};\nstatic const char MOVE_CH[4]  = {'U','D','L','R'};\nstatic const char BUILD_CH[4] = {'u','d','l','r'};\n\nstatic inline int manhattan(int ax,int ay,int bx,int by){\n    return abs(ax-bx)+abs(ay-by);\n}\n\nstruct DoorInfo {\n    int x=-1,y=-1;\n    int inx=-1, iny=-1; // inside neighbor cell (must be in rect)\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<Pet> pets(N);\n    for(int i=0;i<N;i++){\n        cin >> pets[i].x >> pets[i].y >> pets[i].t;\n    }\n    int M;\n    cin >> M;\n    vector<Human> humans(M);\n    for(int i=0;i<M;i++){\n        cin >> humans[i].x >> humans[i].y;\n    }\n\n    auto inside = [&](const Rect& r, int x, int y)->bool{\n        return r.x1 <= x && x <= r.x2 && r.y1 <= y && y <= r.y2;\n    };\n\n    // Build corner rectangles candidates: (h,w) for each corner.\n    // Corner mapping:\n    // 0 TL: rows 1..h, cols 1..w\n    // 1 TR: rows 1..h, cols W-w+1..W\n    // 2 BL: rows H-h+1..H, cols 1..w\n    // 3 BR: rows H-h+1..H, cols W-w+1..W\n    auto make_rect = [&](int corner, int h, int w)->Rect{\n        Rect r;\n        if(corner==0){ r.x1=1; r.x2=h; r.y1=1; r.y2=w; }\n        if(corner==1){ r.x1=1; r.x2=h; r.y1=W-w+1; r.y2=W; }\n        if(corner==2){ r.x1=H-h+1; r.x2=H; r.y1=1; r.y2=w; }\n        if(corner==3){ r.x1=H-h+1; r.x2=H; r.y1=W-w+1; r.y2=W; }\n        return r;\n    };\n\n    // Compute required wall cells to separate rectangle from rest (the \"internal\" sides).\n    auto wall_cells_for = [&](const Rect& r)->vector<pair<int,int>>{\n        vector<pair<int,int>> cells;\n        // top side outside (x1-1) if exists\n        if(r.x1 > 1){\n            int x = r.x1 - 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        // bottom side outside (x2+1) if exists\n        if(r.x2 < H){\n            int x = r.x2 + 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        // left side outside (y1-1) if exists\n        if(r.y1 > 1){\n            int y = r.y1 - 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        // right side outside (y2+1) if exists\n        if(r.y2 < W){\n            int y = r.y2 + 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        return cells;\n    };\n\n    auto choose_door = [&](const Rect& r, const vector<pair<int,int>>& wallCells)->DoorInfo{\n        DoorInfo best;\n        long long bestScore = LLONG_MIN;\n\n        // build a quick set for \"wallCells\" membership\n        static bool isWallCell[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) isWallCell[x][y]=false;\n        for(auto [x,y]: wallCells) isWallCell[x][y]=true;\n\n        for(auto [wx,wy]: wallCells){\n            // find inside neighbor\n            int inx=-1, iny=-1;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(inb(nx,ny) && inside(r,nx,ny)){\n                    inx=nx; iny=ny;\n                    break;\n                }\n            }\n            if(inx==-1) continue; // should not happen\n\n            // Need at least one outside neighbor that is NOT a wall cell (so door is reachable from outside region).\n            bool okOutside=false;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(inside(r,nx,ny)) continue;\n                if(isWallCell[nx][ny]) continue; // would become blocked\n                okOutside=true;\n            }\n            if(!okOutside) continue;\n\n            // Heuristic: maximize distance to pets; minimize total distance from humans to inside-neighbor.\n            int minPetDist = 1000;\n            for(auto &p: pets){\n                minPetDist = min(minPetDist, manhattan(wx,wy,p.x,p.y));\n            }\n            long long sumHumanDist = 0;\n            for(auto &h: humans){\n                sumHumanDist += manhattan(h.x,h.y, inx,iny);\n            }\n\n            // Also avoid doors on the very border if possible (often less reachable).\n            int borderPenalty = (wx==1 || wx==H || wy==1 || wy==W) ? 50 : 0;\n\n            long long score = 200LL*minPetDist - 1LL*sumHumanDist - borderPenalty;\n            if(score > bestScore){\n                bestScore = score;\n                best.x=wx; best.y=wy;\n                best.inx=inx; best.iny=iny;\n            }\n        }\n        return best;\n    };\n\n    auto dist_pet_to_rect = [&](const Rect& r)->int{\n        int best = INF;\n        for(auto &p: pets){\n            int dx = 0;\n            if(p.x < r.x1) dx = r.x1 - p.x;\n            else if(p.x > r.x2) dx = p.x - r.x2;\n            int dy = 0;\n            if(p.y < r.y1) dy = r.y1 - p.y;\n            else if(p.y > r.y2) dy = p.y - r.y2;\n            best = min(best, dx+dy);\n        }\n        return best;\n    };\n\n    auto count_pets_in_rect = [&](const Rect& r)->int{\n        int cnt=0;\n        for(auto &p: pets) if(inside(r,p.x,p.y)) cnt++;\n        return cnt;\n    };\n\n    auto wall_adj_pet_initial_count = [&](const vector<pair<int,int>>& wallCells)->int{\n        int cnt=0;\n        for(auto [x,y]: wallCells){\n            bool adj=false;\n            for(int d=0; d<4; d++){\n                int nx=x+dx4[d], ny=y+dy4[d];\n                if(!inb(nx,ny)) continue;\n                for(auto &p: pets) if(p.x==nx && p.y==ny){ adj=true; break; }\n                if(adj) break;\n            }\n            if(adj) cnt++;\n        }\n        return cnt;\n    };\n\n    // Select best corner rectangle\n    Rect bestRect{1,1,1,1};\n    DoorInfo bestDoor;\n    double bestEval = -1e100;\n\n    for(int corner=0; corner<4; corner++){\n        for(int h=4; h<=30; h++){\n            for(int w=4; w<=30; w++){\n                Rect r = make_rect(corner,h,w);\n                int area = (r.x2-r.x1+1)*(r.y2-r.y1+1);\n                int petsIn = count_pets_in_rect(r);\n                auto wallCells = wall_cells_for(r);\n\n                // If we have walls, pick a door. If door impossible, skip (humans might get stuck outside).\n                DoorInfo door;\n                if(!wallCells.empty()){\n                    door = choose_door(r, wallCells);\n                    if(door.x==-1) continue;\n                }\n\n                // Skip if any initial human/pet is on a wall cell (hard to build early).\n                bool bad=false;\n                for(auto [x,y]: wallCells){\n                    for(auto &p: pets) if(p.x==x && p.y==y) { bad=true; break; }\n                    if(bad) break;\n                    for(auto &hu: humans) if(hu.x==x && hu.y==y) { bad=true; break; }\n                    if(bad) break;\n                }\n                if(bad) continue;\n\n                int minPetToRect = dist_pet_to_rect(r);\n                int adjBad = wall_adj_pet_initial_count(wallCells);\n\n                // Penalize far rectangles (humans must reach it before sealing)\n                int maxHumanDist = 0;\n                for(auto &hu: humans){\n                    int dx = 0;\n                    if(hu.x < r.x1) dx = r.x1 - hu.x;\n                    else if(hu.x > r.x2) dx = hu.x - r.x2;\n                    int dy = 0;\n                    if(hu.y < r.y1) dy = r.y1 - hu.y;\n                    else if(hu.y > r.y2) dy = hu.y - r.y2;\n                    maxHumanDist = max(maxHumanDist, dx+dy);\n                }\n\n                // Core estimate: area * 2^{-petsIn}, with small bonuses/penalties\n                double val = (double)area / 900.0 * pow(0.5, petsIn);\n                val *= pow(0.995, maxHumanDist);\n                val *= (1.0 + 0.03*minPetToRect);\n                val *= pow(0.98, adjBad);\n\n                if(val > bestEval){\n                    bestEval = val;\n                    bestRect = r;\n                    bestDoor = door;\n                }\n            }\n        }\n    }\n\n    Rect rect = bestRect;\n    DoorInfo door = bestDoor;\n\n    // Build target walls (excluding door cell) as \"must become blocked\"\n    static bool blocked[H+1][W+1];\n    static bool targetWall[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n        blocked[x][y]=false;\n        targetWall[x][y]=false;\n    }\n\n    vector<pair<int,int>> wallCells = wall_cells_for(rect);\n    for(auto [x,y]: wallCells) targetWall[x][y] = true;\n    if(door.x!=-1) targetWall[door.x][door.y] = false; // keep as door until closing time\n\n    // Gather point: a step or two inside from door's inside neighbor\n    pair<int,int> gatherPoint;\n    if(door.x!=-1){\n        int gx = door.inx, gy = door.iny;\n        int vx = door.inx - door.x;\n        int vy = door.iny - door.y;\n        int gx2 = gx + vx, gy2 = gy + vy;\n        if(inb(gx2,gy2) && inside(rect,gx2,gy2)){\n            gx=gx2; gy=gy2;\n        }\n        gatherPoint = {gx,gy};\n    } else {\n        // no walls => just go to center\n        gatherPoint = {(rect.x1+rect.x2)/2, (rect.y1+rect.y2)/2};\n    }\n\n    auto compute_occupancy = [&](vector<vector<bool>>& petAt, vector<vector<bool>>& humanAt){\n        petAt.assign(H+1, vector<bool>(W+1,false));\n        humanAt.assign(H+1, vector<bool>(W+1,false));\n        for(auto &p: pets) petAt[p.x][p.y]=true;\n        for(auto &h: humans) humanAt[h.x][h.y]=true;\n    };\n\n    auto canBuild = [&](int tx,int ty,\n                        const vector<vector<bool>>& petAt,\n                        const vector<vector<bool>>& humanAt)->bool{\n        if(!inb(tx,ty)) return false;\n        if(petAt[tx][ty] || humanAt[tx][ty]) return false;\n        // cannot build if any adjacent has a pet\n        for(int d=0; d<4; d++){\n            int nx=tx+dx4[d], ny=ty+dy4[d];\n            if(inb(nx,ny) && petAt[nx][ny]) return false;\n        }\n        return true;\n    };\n\n    auto isMoveAllowed = [&](int x,int y)->bool{\n        if(!inb(x,y)) return false;\n        if(blocked[x][y]) return false;\n        // don't step onto unbuilt wall-cells planned to be blocked later\n        if(targetWall[x][y] && !blocked[x][y]) return false;\n        return true;\n    };\n\n    auto bfs_dist = [&](vector<vector<int>>& dist,\n                        const vector<pair<int,int>>& sources,\n                        function<bool(int,int)> passable){\n        dist.assign(H+1, vector<int>(W+1, INF));\n        deque<pair<int,int>> q;\n        for(auto [sx,sy]: sources){\n            if(!inb(sx,sy)) continue;\n            if(!passable(sx,sy)) continue;\n            dist[sx][sy]=0;\n            q.push_back({sx,sy});\n        }\n        while(!q.empty()){\n            auto [x,y]=q.front(); q.pop_front();\n            int nd = dist[x][y]+1;\n            for(int d=0; d<4; d++){\n                int nx=x+dx4[d], ny=y+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(!passable(nx,ny)) continue;\n                if(dist[nx][ny] > nd){\n                    dist[nx][ny]=nd;\n                    q.push_back({nx,ny});\n                }\n            }\n        }\n    };\n\n    auto step_by_dist = [&](int x,int y, const vector<vector<int>>& dist,\n                            function<bool(int,int)> passable)->char{\n        int bestD = dist[x][y];\n        int bestDir = -1;\n        // deterministic priority U,D,L,R\n        for(int d=0; d<4; d++){\n            int nx=x+dx4[d], ny=y+dy4[d];\n            if(!inb(nx,ny)) continue;\n            if(!passable(nx,ny)) continue;\n            if(dist[nx][ny] < bestD){\n                bestD = dist[nx][ny];\n                bestDir = d;\n            }\n        }\n        if(bestDir==-1) return '.';\n        return MOVE_CH[bestDir];\n    };\n\n    // Main interactive loop\n    for(int turn=0; turn<300; turn++){\n        vector<vector<bool>> petAt, humanAt;\n        compute_occupancy(petAt, humanAt);\n\n        auto insideNow = [&](int x,int y){ return inside(rect,x,y); };\n\n        // remaining wall cells count (excluding door; door handled separately)\n        int remWalls = 0;\n        for(auto [x,y]: wallCells){\n            if(x==door.x && y==door.y) continue;\n            if(targetWall[x][y] && !blocked[x][y]) remWalls++;\n        }\n\n        bool allInside = true;\n        for(auto &h: humans){\n            if(!insideNow(h.x,h.y)){\n                allInside = false;\n                break;\n            }\n        }\n        bool doorExists = (door.x!=-1);\n        bool doorClosed = doorExists ? blocked[door.x][door.y] : true;\n\n        // Build goal positions inside rectangle adjacent to remaining wall cells\n        vector<pair<int,int>> buildGoals;\n        if(remWalls > 0){\n            static bool goalMark[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) goalMark[x][y]=false;\n\n            for(auto [wx,wy]: wallCells){\n                if(wx==door.x && wy==door.y) continue;\n                if(!targetWall[wx][wy] || blocked[wx][wy]) continue;\n                for(int d=0; d<4; d++){\n                    int nx=wx+dx4[d], ny=wy+dy4[d];\n                    if(!inb(nx,ny)) continue;\n                    if(!insideNow(nx,ny)) continue;\n                    if(blocked[nx][ny]) continue;\n                    // inside cells are never targetWall, but keep generic:\n                    if(targetWall[nx][ny] && !blocked[nx][ny]) continue;\n                    if(!goalMark[nx][ny]){\n                        goalMark[nx][ny]=true;\n                        buildGoals.push_back({nx,ny});\n                    }\n                }\n            }\n        }\n\n        // Dist maps\n        vector<vector<int>> distGather, distBuild;\n        // gather BFS over whole board with move-allowed, but door cell must be allowed too.\n        auto passGather = [&](int x,int y)->bool{\n            if(!inb(x,y)) return false;\n            if(blocked[x][y]) return false;\n            if(targetWall[x][y] && !blocked[x][y]) return false;\n            // Door cell is not targetWall, so allowed here.\n            return true;\n        };\n        bfs_dist(distGather, {gatherPoint}, passGather);\n\n        auto passBuild = [&](int x,int y)->bool{\n            if(!insideNow(x,y)) return false;\n            return passGather(x,y);\n        };\n        if(!buildGoals.empty()){\n            bfs_dist(distBuild, buildGoals, passBuild);\n        } else {\n            distBuild.assign(H+1, vector<int>(W+1, INF));\n        }\n\n        // Decide actions\n        vector<char> act(M, '.');\n\n        // 1) If ready to close door, do it (highest priority).\n        bool willCloseDoor = false;\n        if(doorExists && !doorClosed && remWalls==0 && allInside){\n            // ensure nobody is on the door cell\n            bool someoneOnDoor = false;\n            for(auto &h: humans){\n                if(h.x==door.x && h.y==door.y) { someoneOnDoor=true; break; }\n            }\n            if(!someoneOnDoor && canBuild(door.x, door.y, petAt, humanAt)){\n                // find an adjacent human (should be inside neighbor area)\n                for(int i=0;i<M;i++){\n                    int hx=humans[i].x, hy=humans[i].y;\n                    if(manhattan(hx,hy,door.x,door.y)==1){\n                        // build direction from human to door\n                        for(int d=0; d<4; d++){\n                            if(hx+dx4[d]==door.x && hy+dy4[d]==door.y){\n                                act[i] = BUILD_CH[d];\n                                willCloseDoor = true;\n                                break;\n                            }\n                        }\n                        if(willCloseDoor) break;\n                    }\n                }\n            }\n            // If cannot close now, we just keep trying in later turns.\n        }\n\n        // 2) Build remaining walls for humans inside (if adjacent)\n        // Note: door-close action already decided for one human; others can still build.\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n            if(!insideNow(hx,hy)) continue;\n\n            for(int d=0; d<4; d++){\n                int tx=hx+dx4[d], ty=hy+dy4[d];\n                if(!inb(tx,ty)) continue;\n                if(targetWall[tx][ty] && !blocked[tx][ty]){\n                    if(canBuild(tx,ty,petAt,humanAt)){\n                        act[i] = BUILD_CH[d];\n                        break;\n                    }\n                }\n            }\n        }\n\n        // 3) Move:\n        // - outside humans: toward gather point\n        // - inside humans: toward build goals if walls remain, else idle\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            if(!insideNow(hx,hy)){\n                // If currently standing on the door cell (possible while entering), move into rectangle ASAP.\n                if(doorExists && hx==door.x && hy==door.y){\n                    // move to inside neighbor (door.inx, door.iny) if possible\n                    int tx=door.inx, ty=door.iny;\n                    // determine direction\n                    for(int d=0; d<4; d++){\n                        if(hx+dx4[d]==tx && hy+dy4[d]==ty && passGather(tx,ty)){\n                            act[i] = MOVE_CH[d];\n                            break;\n                        }\n                    }\n                    if(act[i]=='.'){\n                        // fallback: follow gather dist\n                        act[i] = step_by_dist(hx,hy,distGather,passGather);\n                    }\n                } else {\n                    act[i] = step_by_dist(hx,hy,distGather,passGather);\n                }\n            } else {\n                if(remWalls > 0 && distBuild[hx][hy] < INF){\n                    act[i] = step_by_dist(hx,hy,distBuild,passBuild);\n                } else {\n                    act[i] = '.';\n                }\n            }\n        }\n\n        // Output actions\n        string out;\n        out.reserve(M);\n        for(int i=0;i<M;i++) out.push_back(act[i]);\n        cout << out << \"\\n\" << flush;\n\n        // Simulate our humans/walls update locally (to keep our state consistent)\n        // Compute occupancy at start-of-turn already in humanAt/petAt, used for legality.\n        // Apply builds (successful ones)\n        static bool willBeBlocked[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) willBeBlocked[x][y]=false;\n\n        for(int i=0;i<M;i++){\n            char c = act[i];\n            if(c=='u' || c=='d' || c=='l' || c=='r'){\n                int d = (c=='u'?0: c=='d'?1: c=='l'?2:3);\n                int tx = humans[i].x + dx4[d];\n                int ty = humans[i].y + dy4[d];\n                if(inb(tx,ty) && canBuild(tx,ty,petAt,humanAt)){\n                    willBeBlocked[tx][ty] = true;\n                }\n            }\n        }\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n            if(willBeBlocked[x][y]) blocked[x][y]=true;\n        }\n\n        // Apply moves (avoid moving into newly blocked cells)\n        for(int i=0;i<M;i++){\n            char c = act[i];\n            int d=-1;\n            if(c=='U') d=0;\n            if(c=='D') d=1;\n            if(c=='L') d=2;\n            if(c=='R') d=3;\n            if(d!=-1){\n                int nx = humans[i].x + dx4[d];\n                int ny = humans[i].y + dy4[d];\n                if(inb(nx,ny) && !blocked[nx][ny] && !willBeBlocked[nx][ny]){\n                    humans[i].x = nx;\n                    humans[i].y = ny;\n                }\n            }\n        }\n\n        // Read pets' movements and update pets\n        for(int i=0;i<N;i++){\n            string s;\n            if(!(cin >> s)) return 0; // end (safety)\n            if(s==\".\" ) continue;\n            for(char c: s){\n                int d=-1;\n                if(c=='U') d=0;\n                if(c=='D') d=1;\n                if(c=='L') d=2;\n                if(c=='R') d=3;\n                if(d==-1) continue;\n                int nx = pets[i].x + dx4[d];\n                int ny = pets[i].y + dy4[d];\n                if(inb(nx,ny) && !blocked[nx][ny]){\n                    pets[i].x = nx;\n                    pets[i].y = ny;\n                }\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int V = N * N;\nstatic constexpr int INF = 1e9;\n\nstruct Meta {\n    int parent;\n    char mv;\n};\n\nstruct Cand {\n    int meta;\n    double exp;   // accumulated expected score so far\n    double key;   // beam ranking key (heuristic)\n    float rem;    // remaining probability mass not yet reached\n    array<float, V> prob; // distribution over non-target states\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj, ti, tj;\n    double p;\n    cin >> si >> sj >> ti >> tj >> p;\n\n    vector<string> h(N);\n    for (int i = 0; i < N; i++) cin >> h[i]; // length 19\n    vector<string> v(N - 1);\n    for (int i = 0; i < N - 1; i++) cin >> v[i]; // length 20\n\n    auto id = [&](int r, int c) { return r * N + c; };\n    int s = id(si, sj);\n    int t = id(ti, tj);\n\n    // Precompute successful-move transitions (if wall/boundary => stay).\n    int nxt[V][4];\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int cur = id(r, c);\n        // U\n        if (r == 0) nxt[cur][0] = cur;\n        else nxt[cur][0] = (v[r-1][c] == '0') ? id(r-1, c) : cur;\n        // D\n        if (r == N-1) nxt[cur][1] = cur;\n        else nxt[cur][1] = (v[r][c] == '0') ? id(r+1, c) : cur;\n        // L\n        if (c == 0) nxt[cur][2] = cur;\n        else nxt[cur][2] = (h[r][c-1] == '0') ? id(r, c-1) : cur;\n        // R\n        if (c == N-1) nxt[cur][3] = cur;\n        else nxt[cur][3] = (h[r][c] == '0') ? id(r, c+1) : cur;\n    }\n\n    // BFS distances to target (ignoring forgetting).\n    vector<int> dist(V, INF);\n    {\n        deque<int> dq;\n        dist[t] = 0;\n        dq.push_back(t);\n        while (!dq.empty()) {\n            int x = dq.front(); dq.pop_front();\n            int dx = dist[x] + 1;\n            for (int d = 0; d < 4; d++) {\n                int y = nxt[x][d];\n                if (y == x) continue;\n                if (dist[y] > dx) {\n                    dist[y] = dx;\n                    dq.push_back(y);\n                }\n            }\n        }\n    }\n\n    const char dc[4] = {'U','D','L','R'};\n    double q = 1.0 - p;\n\n    // Beam width: slightly larger for bigger p.\n    int W = (p >= 0.30 ? 700 : 600);\n    int keepH = (W * 3) / 4; // keep by heuristic\n    int keepE = W - keepH;   // also keep by exp to avoid heuristic mistakes\n\n    vector<Meta> meta;\n    meta.reserve(300000);\n    meta.push_back({-1, '?'});\n\n    // Initial candidate.\n    vector<Cand> cur;\n    cur.reserve(W);\n    Cand root;\n    root.meta = 0;\n    root.exp = 0.0;\n    root.key = 0.0;\n    root.rem = 1.0f;\n    root.prob.fill(0.0f);\n    root.prob[s] = 1.0f;\n    if (s == t) {\n        // Not possible per constraints, but handle anyway.\n        root.prob[s] = 0.0f;\n        root.rem = 0.0f;\n    }\n    cur.push_back(root);\n\n    int depth_done = 0;\n\n    for (int depth = 0; depth < 200; depth++) {\n        depth_done = depth;\n        vector<Cand> nxtCands;\n        nxtCands.reserve(cur.size() * 4);\n\n        bool anyRem = false;\n        for (auto &c : cur) if (c.rem > 1e-12f) { anyRem = true; break; }\n        if (!anyRem) break; // everyone already reaches with prob ~1\n\n        for (const auto &c : cur) {\n            if (c.rem < 1e-12f) continue;\n\n            for (int d = 0; d < 4; d++) {\n                Cand ch;\n                ch.prob.fill(0.0f);\n                double hit = 0.0;\n\n                // Transition update.\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = c.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    int np = nxt[pos][d];\n                    if (np == pos) {\n                        ch.prob[pos] += prf; // wall/boundary => always stay\n                    } else {\n                        double pr = (double)prf;\n                        double mv = pr * q;\n                        double st = pr * p;\n                        if (np == t) hit += mv;\n                        else ch.prob[np] += (float)mv;\n                        ch.prob[pos] += (float)st;\n                    }\n                }\n\n                int turn = depth + 1;\n                ch.exp = c.exp + hit * (401.0 - turn);\n\n                // Compute remaining mass and distance stats.\n                double rem = 0.0;\n                double sumd = 0.0;\n                int mind = INF;\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = ch.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    rem += prf;\n                    if (prf > 1e-12f) {\n                        sumd += (double)prf * dist[pos];\n                        mind = min(mind, dist[pos]);\n                    }\n                }\n                ch.rem = (float)rem;\n\n                // Heuristic: current exp + estimated remaining gain based on avg BFS dist.\n                double key = ch.exp;\n                int remainingSteps = 200 - turn;\n                if (rem > 1e-12 && mind <= remainingSteps) {\n                    double avgd = sumd / max(rem, 1e-12);\n                    double estTime = (double)turn + avgd / max(1e-6, q);\n                    estTime = min(estTime, 200.0); // can't arrive after horizon\n                    double estAdd = rem * (401.0 - estTime);\n                    double optimisticAdd = rem * (401.0 - (double)turn);\n                    // Blend: guidance + optimism.\n                    key = ch.exp + 0.70 * max(0.0, estAdd) + 0.30 * max(0.0, optimisticAdd);\n                }\n                ch.key = key;\n\n                // Meta/pointer for reconstruction.\n                meta.push_back({c.meta, dc[d]});\n                ch.meta = (int)meta.size() - 1;\n\n                nxtCands.push_back(std::move(ch));\n            }\n        }\n\n        if (nxtCands.empty()) break;\n\n        // Select beam: combine top by heuristic and top by exp.\n        int M = (int)nxtCands.size();\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n\n        vector<char> chosen(M, 0);\n        vector<int> picked;\n        picked.reserve(min(W, M));\n\n        auto cmpKey = [&](int a, int b) { return nxtCands[a].key > nxtCands[b].key; };\n        auto cmpExp = [&](int a, int b) { return nxtCands[a].exp > nxtCands[b].exp; };\n\n        int takeH = min(keepH, M);\n        nth_element(idx.begin(), idx.begin() + takeH, idx.end(), cmpKey);\n        idx.resize(takeH);\n        sort(idx.begin(), idx.end(), cmpKey);\n        for (int k = 0; k < (int)idx.size() && (int)picked.size() < W; k++) {\n            int i = idx[k];\n            if (!chosen[i]) {\n                chosen[i] = 1;\n                picked.push_back(i);\n            }\n        }\n\n        // fill remaining slots by exp\n        if ((int)picked.size() < W) {\n            vector<int> idx2(M);\n            iota(idx2.begin(), idx2.end(), 0);\n            int need = min(keepE, W - (int)picked.size());\n            nth_element(idx2.begin(), idx2.begin() + need, idx2.end(), cmpExp);\n            idx2.resize(need);\n            sort(idx2.begin(), idx2.end(), cmpExp);\n            for (int k = 0; k < (int)idx2.size() && (int)picked.size() < W; k++) {\n                int i = idx2[k];\n                if (!chosen[i]) {\n                    chosen[i] = 1;\n                    picked.push_back(i);\n                }\n            }\n        }\n\n        // Build next beam.\n        vector<Cand> nb;\n        nb.reserve(picked.size());\n        for (int i : picked) nb.push_back(std::move(nxtCands[i]));\n        cur.swap(nb);\n    }\n\n    // Choose best by exact accumulated expected score among the final beam.\n    int bestMeta = cur[0].meta;\n    double bestExp = cur[0].exp;\n    for (auto &c : cur) {\n        if (c.exp > bestExp) {\n            bestExp = c.exp;\n            bestMeta = c.meta;\n        }\n    }\n\n    // Reconstruct move string.\n    string ans;\n    int x = bestMeta;\n    while (x != 0) {\n        ans.push_back(meta[x].mv);\n        x = meta[x].parent;\n    }\n    reverse(ans.begin(), ans.end());\n\n    // Ensure length 200 (safe: extending cannot reduce expected score).\n    if ((int)ans.size() < 200) ans.append(200 - ans.size(), 'U');\n    if ((int)ans.size() > 200) ans.resize(200); // should not happen, but just in case\n\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TILES = N * N;\nstatic constexpr int PORTS = TILES * 4;\n\n// Fast RNG (xorshift)\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU64() % (uint64_t)(hi - lo + 1));\n    }\n    inline double nextDouble() { // [0,1)\n        // 53-bit mantissa\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct EvalResult {\n    long long baseScore;   // L1 * L2 (true score for this single test)\n    int L1, L2;\n    long long sumSq;       // sum of len^2 over all loops\n    int matchedEdges;      // number of matched borders (external edges)\n    int openEnds;          // number of endpoints with degree 1\n    int loopCount;\n    double energy;         // SA energy (higher is better)\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read input tiles (as digits '0'..'7')\n    vector<uint8_t> initState(TILES);\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            initState[i * N + j] = (uint8_t)(s[j] - '0');\n        }\n    }\n\n    // Rotation map after 90 deg CCW\n    // 0->1->2->3->0, 4<->5, 6<->7\n    array<uint8_t, 8> rot1 = {1,2,3,0,5,4,7,6};\n\n    // rotStep[t][k] = state after rotating state t by k*90deg CCW\n    uint8_t rotStep[8][4];\n    for (int t = 0; t < 8; t++) {\n        rotStep[t][0] = (uint8_t)t;\n        rotStep[t][1] = rot1[t];\n        rotStep[t][2] = rot1[rotStep[t][1]];\n        rotStep[t][3] = rot1[rotStep[t][2]];\n    }\n\n    // Side masks (bits: 0=L, 1=U, 2=R, 3=D)\n    // and internal connections (pairs of sides).\n    uint8_t sideMask[8];\n    uint8_t pairCnt[8];\n    uint8_t pairs[8][2][2]; // up to 2 segments\n\n    auto set1 = [&](int t, int a, int b, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 1;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = pairs[t][1][1] = 255;\n    };\n    auto set2 = [&](int t, int a, int b, int c, int d, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 2;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = (uint8_t)c;\n        pairs[t][1][1] = (uint8_t)d;\n    };\n\n    // 0: L-U\n    set1(0, 0, 1, (1u<<0) | (1u<<1));\n    // 1: L-D\n    set1(1, 0, 3, (1u<<0) | (1u<<3));\n    // 2: R-D\n    set1(2, 2, 3, (1u<<2) | (1u<<3));\n    // 3: U-R\n    set1(3, 1, 2, (1u<<1) | (1u<<2));\n    // 4: (L-U) and (R-D)\n    set2(4, 0, 1, 2, 3, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 5: (L-D) and (U-R)\n    set2(5, 0, 3, 1, 2, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 6: L-R\n    set1(6, 0, 2, (1u<<0) | (1u<<2));\n    // 7: U-D\n    set1(7, 1, 3, (1u<<1) | (1u<<3));\n\n    // Current solution representation\n    vector<uint8_t> curRot(TILES, 0);     // 0..3\n    vector<uint8_t> curState(TILES, 0);   // 0..7 (actual oriented state)\n    vector<uint8_t> curMask(TILES, 0);    // side mask for curState\n\n    // Build initial random + greedy local matching\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift64 rng(seed);\n\n    auto applyFromInit = [&](int idx, uint8_t r) -> uint8_t {\n        uint8_t st = initState[idx];\n        return rotStep[st][r & 3];\n    };\n\n    for (int p = 0; p < TILES; p++) {\n        uint8_t r = (uint8_t)rng.nextInt(0, 3);\n        curRot[p] = r;\n        curState[p] = applyFromInit(p, r);\n        curMask[p] = sideMask[curState[p]];\n    }\n\n    // Greedy sweeps: encourage (active/inactive) agreement on borders and avoid boundary leaks\n    vector<int> order(TILES);\n    iota(order.begin(), order.end(), 0);\n\n    auto localScore = [&](int p, uint8_t mCand) -> int {\n        int i = p / N, j = p % N;\n        int sc = 0;\n        // dir 0:L,1:U,2:R,3:D, opposite is d^2\n        // For each direction: if neighbor exists, reward equality (both active or both inactive)\n        // Boundary: penalize active side going outside.\n        // left\n        {\n            bool a = (mCand >> 0) & 1;\n            if (j == 0) sc += a ? -2 : 0;\n            else {\n                bool b = (curMask[p - 1] >> 2) & 1;\n                sc += (a == b) ? 1 : -1;\n            }\n        }\n        // up\n        {\n            bool a = (mCand >> 1) & 1;\n            if (i == 0) sc += a ? -2 : 0;\n            else {\n                bool b = (curMask[p - N] >> 3) & 1;\n                sc += (a == b) ? 1 : -1;\n            }\n        }\n        // right\n        {\n            bool a = (mCand >> 2) & 1;\n            if (j == N - 1) sc += a ? -2 : 0;\n            else {\n                bool b = (curMask[p + 1] >> 0) & 1;\n                sc += (a == b) ? 1 : -1;\n            }\n        }\n        // down\n        {\n            bool a = (mCand >> 3) & 1;\n            if (i == N - 1) sc += a ? -2 : 0;\n            else {\n                bool b = (curMask[p + N] >> 1) & 1;\n                sc += (a == b) ? 1 : -1;\n            }\n        }\n        return sc;\n    };\n\n    for (int sweep = 0; sweep < 6; sweep++) {\n        // random order each sweep\n        for (int i = TILES - 1; i > 0; i--) {\n            int j = (int)(rng.nextU64() % (uint64_t)(i + 1));\n            swap(order[i], order[j]);\n        }\n        for (int idx = 0; idx < TILES; idx++) {\n            int p = order[idx];\n            int bestSc = INT_MIN;\n            uint8_t bestDelta = 0;\n            // test 4 rotations relative to current state\n            for (uint8_t dlt = 0; dlt < 4; dlt++) {\n                uint8_t sCand = rotStep[curState[p]][dlt];\n                uint8_t mCand = sideMask[sCand];\n                int sc = localScore(p, mCand);\n                if (sc > bestSc || (sc == bestSc && rng.nextInt(0, 3) == 0)) {\n                    bestSc = sc;\n                    bestDelta = dlt;\n                }\n            }\n            if (bestDelta != 0) {\n                curRot[p] = (uint8_t)((curRot[p] + bestDelta) & 3);\n                curState[p] = rotStep[curState[p]][bestDelta];\n                curMask[p] = sideMask[curState[p]];\n            }\n        }\n    }\n\n    // Evaluation: build endpoint graph each time (deg<=2), find cycle components, compute L1/L2.\n    static int degArr[PORTS];\n    static int nb1[PORTS];\n    static int nb2[PORTS];\n    static uint8_t vis[PORTS];\n    static int stackBuf[PORTS];\n\n    auto addEdge = [&](int u, int v) {\n        int du = degArr[u]++;\n        if (du == 0) nb1[u] = v;\n        else nb2[u] = v;\n\n        int dv = degArr[v]++;\n        if (dv == 0) nb1[v] = u;\n        else nb2[v] = u;\n    };\n\n    auto evaluate = [&]() -> EvalResult {\n        // reset\n        memset(degArr, 0, sizeof(degArr));\n        // set nb to -1\n        for (int i = 0; i < PORTS; i++) {\n            nb1[i] = -1;\n            nb2[i] = -1;\n            vis[i] = 0;\n        }\n\n        // internal edges\n        for (int p = 0; p < TILES; p++) {\n            int base = p * 4;\n            uint8_t st = curState[p];\n            uint8_t cnt = pairCnt[st];\n            for (uint8_t k = 0; k < cnt; k++) {\n                int a = pairs[st][k][0];\n                int b = pairs[st][k][1];\n                addEdge(base + a, base + b);\n            }\n        }\n\n        // external edges (matched borders)\n        int matchedEdges = 0;\n        // horizontal\n        for (int i = 0; i < N; i++) {\n            int row = i * N;\n            for (int j = 0; j < N - 1; j++) {\n                int p = row + j;\n                int q = p + 1;\n                if ((curMask[p] & (1u << 2)) && (curMask[q] & (1u << 0))) {\n                    addEdge(p * 4 + 2, q * 4 + 0);\n                    matchedEdges++;\n                }\n            }\n        }\n        // vertical\n        for (int i = 0; i < N - 1; i++) {\n            int row = i * N;\n            int row2 = (i + 1) * N;\n            for (int j = 0; j < N; j++) {\n                int p = row + j;\n                int q = row2 + j;\n                if ((curMask[p] & (1u << 3)) && (curMask[q] & (1u << 1))) {\n                    addEdge(p * 4 + 3, q * 4 + 1);\n                    matchedEdges++;\n                }\n            }\n        }\n\n        // count open ends (degree 1 endpoints)\n        int openEnds = 0;\n        for (int u = 0; u < PORTS; u++) if (degArr[u] == 1) openEnds++;\n\n        // find cycle components\n        int L1 = 0, L2 = 0;\n        int loopCount = 0;\n        long long sumSq = 0;\n\n        for (int s = 0; s < PORTS; s++) {\n            if (degArr[s] == 0 || vis[s]) continue;\n            int top = 0;\n            stackBuf[top++] = s;\n            vis[s] = 1;\n            int compSize = 0;\n            bool isCycle = true;\n\n            while (top) {\n                int x = stackBuf[--top];\n                compSize++;\n                if (degArr[x] != 2) isCycle = false;\n                int a = nb1[x], b = nb2[x];\n                if (a != -1 && !vis[a]) { vis[a] = 1; stackBuf[top++] = a; }\n                if (b != -1 && !vis[b]) { vis[b] = 1; stackBuf[top++] = b; }\n            }\n\n            if (isCycle) {\n                int len = compSize / 2; // length in \"moves to adjacent tile\"\n                loopCount++;\n                sumSq += 1LL * len * len;\n\n                if (len > L1) { L2 = L1; L1 = len; }\n                else if (len > L2) { L2 = len; }\n            }\n        }\n\n        long long base = (loopCount >= 2) ? 1LL * L1 * L2 : 0LL;\n\n        // SA energy: true score dominates, but aux terms guide creation/closure of cycles.\n        // Tuned to keep magnitudes reasonable.\n        double energy = base * 10.0 + sumSq * 0.2 + matchedEdges * 1.0 - openEnds * 2.0;\n\n        return EvalResult{base, L1, L2, sumSq, matchedEdges, openEnds, loopCount, energy};\n    };\n\n    EvalResult curEval = evaluate();\n    long long bestBase = curEval.baseScore;\n    vector<uint8_t> bestRot = curRot;\n\n    // Simulated annealing\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.93; // seconds (keep margin)\n    const double T0 = 50000.0;\n    const double T1 = 500.0;\n\n    long long iter = 0;\n    while (true) {\n        iter++;\n        if ((iter & 1023) == 0) {\n            double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (sec >= TL) break;\n        }\n\n        int p = (int)(rng.nextU64() % TILES);\n\n        uint8_t oldR = curRot[p];\n        uint8_t oldS = curState[p];\n        uint8_t oldM = curMask[p];\n\n        // choose delta that changes state (avoid waste on period-2 tiles)\n        uint8_t delta = (uint8_t)(1 + (rng.nextU32() % 3));\n        uint8_t newS = rotStep[oldS][delta];\n        if (newS == oldS) {\n            // for period-2 tiles, delta=2 does nothing; force 1\n            delta = 1;\n            newS = rotStep[oldS][delta];\n        }\n\n        curRot[p] = (uint8_t)((oldR + delta) & 3);\n        curState[p] = newS;\n        curMask[p] = sideMask[newS];\n\n        EvalResult nxtEval = evaluate();\n\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = min(1.0, sec / TL);\n        double Temp = T0 * pow(T1 / T0, t);\n\n        double diff = nxtEval.energy - curEval.energy;\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else {\n            double prob = exp(diff / Temp);\n            accept = (rng.nextDouble() < prob);\n        }\n\n        if (accept) {\n            curEval = nxtEval;\n            if (nxtEval.baseScore > bestBase) {\n                bestBase = nxtEval.baseScore;\n                bestRot = curRot;\n            }\n        } else {\n            curRot[p] = oldR;\n            curState[p] = oldS;\n            curMask[p] = oldM;\n        }\n    }\n\n    // Output best rotations as 900-char string\n    string out;\n    out.reserve(TILES);\n    for (int p = 0; p < TILES; p++) out.push_back(char('0' + (bestRot[p] & 3)));\n    cout << out << \"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift64(uint64_t seed = 0) {\n        if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL;\n    }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline int hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int potential = 0;\n    int edgesTotal = 0;\n    int cycleSurplus = 0;\n    int largestComp = 0;\n    long long obj = 0;\n};\n\nstruct Solver {\n    int N, T;\n    int V; // N*N-1\n    vector<uint8_t> init;\n    int initBlank = -1;\n\n    // directions: 0=U,1=D,2=L,3=R  (blank moves)\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char dch[4] = {'U','D','L','R'};\n    const int opp[4] = {1,0,3,2};\n\n    Metrics evaluate(const vector<uint8_t>& b) const {\n        int NN = N * N;\n        atcoder::dsu dsu(NN);\n        // list edges after unions to count edges per component leader\n        array<pair<int,int>, 256> edges; // max edges <= 2*N*(N-1) <= 180 for N=10\n        int eidx = 0;\n\n        auto idx = [&](int r, int c){ return r*N + c; };\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int u = idx(r,c);\n                uint8_t tu = b[u];\n                if (tu == 0) continue;\n                if (c + 1 < N) {\n                    int v = u + 1;\n                    uint8_t tv = b[v];\n                    if (tv != 0 && (tu & 4) && (tv & 1)) {\n                        dsu.merge(u, v);\n                        edges[eidx++] = {u, v};\n                    }\n                }\n                if (r + 1 < N) {\n                    int v = u + N;\n                    uint8_t tv = b[v];\n                    if (tv != 0 && (tu & 8) && (tv & 2)) {\n                        dsu.merge(u, v);\n                        edges[eidx++] = {u, v};\n                    }\n                }\n            }\n        }\n\n        vector<int> vcnt(NN, 0), ecnt(NN, 0);\n        for (int i = 0; i < NN; i++) {\n            if (b[i] != 0) vcnt[dsu.leader(i)]++;\n        }\n        for (int k = 0; k < eidx; k++) {\n            int u = edges[k].first;\n            int rt = dsu.leader(u);\n            ecnt[rt]++;\n        }\n\n        Metrics m;\n        m.largestTree = 0;\n        m.potential = 0;\n        m.edgesTotal = 0;\n        m.cycleSurplus = 0;\n        m.largestComp = 0;\n\n        for (int i = 0; i < NN; i++) {\n            if (vcnt[i] == 0) continue;\n            int Vc = vcnt[i];\n            int Ec = ecnt[i];\n            m.edgesTotal += Ec;\n            m.largestComp = max(m.largestComp, Vc);\n\n            int extra = max(0, Ec - (Vc - 1));\n            m.cycleSurplus += extra;\n\n            if (extra == 0) m.largestTree = max(m.largestTree, Vc);\n\n            int pot = Vc - 2 * extra;\n            m.potential = max(m.potential, pot);\n        }\n\n        // Objective: prioritize \"actual best tree size\", then \"almost-tree potential\"\n        // plus matched edges, minus cycle surplus.\n        m.obj = 0;\n        m.obj += (long long)m.largestTree * 1000000LL;\n        m.obj += (long long)m.potential * 10000LL;\n        m.obj += (long long)m.edgesTotal * 200LL;\n        m.obj -= (long long)m.cycleSurplus * 30000LL;\n        m.obj += (long long)m.largestComp; // tiny tie-break\n        return m;\n    }\n\n    // apply move d to board b and blank position (in-place), assumes legal\n    static inline void do_move_inplace(int N, vector<uint8_t>& b, int& blank, int d,\n                                       const int dr[4], const int dc[4]) {\n        int r = blank / N, c = blank % N;\n        int nr = r + dr[d], nc = c + dc[d];\n        int nb = nr * N + nc;\n        swap(b[blank], b[nb]);\n        blank = nb;\n    }\n\n    string run_once(XorShift64& rng, double time_frac) const {\n        vector<uint8_t> b = init;\n        int blank = initBlank;\n\n        // Temperature schedule (softmax). We make it depend slightly on run index via time_frac.\n        // Larger at early runs.\n        double T0 = 4.0e6 * (0.6 + 0.4 * (1.0 - time_frac));\n        double T1 = 2.0e5;\n\n        string path;\n        path.reserve(T);\n\n        Metrics cur = evaluate(b);\n        int bestS = cur.largestTree;\n        int bestLen = 0; // 0 moves\n        // if perfect achieved, we'd prefer shortest prefix\n        int target = V;\n\n        int prevd = -1;\n\n        for (int step = 0; step < T; step++) {\n            // enumerate legal moves\n            int r = blank / N, c = blank % N;\n            int cand[4], cc = 0;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) cand[cc++] = d;\n            }\n\n            // optional: avoid immediate reverse often\n            if (prevd != -1 && cc >= 2) {\n                if (rng.next_double() < 0.75) {\n                    int rev = opp[prevd];\n                    int nc = 0;\n                    for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                    if (nc >= 1) cc = nc;\n                }\n            }\n\n            // evaluate candidates\n            Metrics mets[4];\n            long long objs[4];\n            long long maxObj = LLONG_MIN;\n\n            for (int i = 0; i < cc; i++) {\n                int d = cand[i];\n                int savedBlank = blank;\n                do_move_inplace(N, b, blank, d, dr, dc);\n                mets[i] = evaluate(b);\n                objs[i] = mets[i].obj;\n                maxObj = max(maxObj, objs[i]);\n                // revert\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n            }\n\n            double temp = T0 + (T1 - T0) * (double)step / max(1, T - 1);\n\n            // softmax sampling\n            double wsum = 0.0;\n            double w[4];\n            for (int i = 0; i < cc; i++) {\n                double x = (double)(objs[i] - maxObj) / temp;\n                // avoid underflow to 0 too much\n                x = max(x, -60.0);\n                w[i] = exp(x);\n                wsum += w[i];\n            }\n            double pick = rng.next_double() * wsum;\n            int choose = 0;\n            for (int i = 0; i < cc; i++) {\n                pick -= w[i];\n                if (pick <= 0) { choose = i; break; }\n            }\n\n            int d = cand[choose];\n            do_move_inplace(N, b, blank, d, dr, dc);\n            path.push_back(dch[d]);\n            prevd = d;\n            cur = mets[choose];\n\n            // update best prefix in this run\n            int S = cur.largestTree;\n            int len = step + 1;\n            if (S > bestS) {\n                bestS = S;\n                bestLen = len;\n            } else if (S == bestS) {\n                if (S == target && len < bestLen) bestLen = len;\n            }\n\n            // early exit if we already got perfect very early\n            if (bestS == target && bestLen <= N * N) {\n                // still might find even shorter, but usually rare; keep walking a bit?\n                // We'll just continue; final global multi-start chooses best.\n            }\n        }\n        return path.substr(0, bestLen);\n    }\n\n    string solve() {\n        V = N * N - 1;\n\n        // Multi-start within time limit\n        auto start = chrono::high_resolution_clock::now();\n        const double TL = 2.85; // seconds, safety margin\n\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        string bestAns;\n        int bestS = 0;\n        int bestLen = 0;\n\n        // Always consider empty output too\n        {\n            Metrics m0 = evaluate(init);\n            bestS = m0.largestTree;\n            bestLen = 0;\n            bestAns = \"\";\n        }\n\n        int runs = 0;\n        while (true) {\n            auto now = chrono::high_resolution_clock::now();\n            double elapsed = chrono::duration<double>(now - start).count();\n            if (elapsed >= TL) break;\n\n            double frac = elapsed / TL;\n            string cand = run_once(rng, frac);\n\n            // evaluate cand's final state? We tracked best prefix by construction, so cand is best prefix.\n            // To compare, we need its S. Re-simulate cand quickly.\n            vector<uint8_t> b = init;\n            int blank = initBlank;\n            for (char ch : cand) {\n                int d = 0;\n                if (ch=='U') d=0;\n                else if (ch=='D') d=1;\n                else if (ch=='L') d=2;\n                else d=3;\n                do_move_inplace(N, b, blank, d, dr, dc);\n            }\n            Metrics m = evaluate(b);\n\n            int S = m.largestTree;\n            int L = (int)cand.size();\n            if (S > bestS) {\n                bestS = S;\n                bestLen = L;\n                bestAns = cand;\n            } else if (S == bestS) {\n                // if perfect, prefer shorter; otherwise doesn't matter much but shorter is fine\n                if (S == V) {\n                    if (L < bestLen) {\n                        bestLen = L;\n                        bestAns = cand;\n                    }\n                } else {\n                    if (L < bestLen) {\n                        bestLen = L;\n                        bestAns = cand;\n                    }\n                }\n            }\n\n            runs++;\n        }\n\n        // Ensure within T\n        if ((int)bestAns.size() > T) bestAns.resize(T);\n        return bestAns;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.T;\n    int N = solver.N;\n    solver.init.assign(N*N, 0);\n\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            int v = hexval(s[j]);\n            solver.init[i*N + j] = (uint8_t)v;\n            if (v == 0) solver.initBlank = i*N + j;\n        }\n    }\n\n    string ans = solver.solve();\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int R = 10000;\nstatic constexpr long long LEN = 100000000LL; // 1e8, endpoints far away but within 1e9\n\n// ---------------- RNG ----------------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline double uniform01() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double uniform(double lo, double hi) {\n        return lo + (hi - lo) * uniform01();\n    }\n    inline int uniformInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// ---------------- Geometry / signature ----------------\nstruct Point {\n    int x, y;\n};\n\nstruct Line {\n    // parameters for mutation\n    double theta; // [0, pi)\n    double u;     // signed distance along normal (normal is unit)\n    // integer endpoints for exact side test\n    long long px, py, qx, qy;\n};\n\nstruct Key {\n    uint64_t lo = 0, hi = 0;\n    bool operator==(Key const& o) const noexcept { return lo == o.lo && hi == o.hi; }\n};\n\nstruct KeyHash {\n    size_t operator()(Key const& k) const noexcept {\n        uint64_t h = k.lo ^ splitmix64(k.hi + 0x9e3779b97f4a7c15ULL);\n        return (size_t)splitmix64(h);\n    }\n};\n\nstatic inline int getBit(const Key& k, int idx) {\n    if (idx < 64) return (int)((k.lo >> idx) & 1ULL);\n    return (int)((k.hi >> (idx - 64)) & 1ULL);\n}\nstatic inline void setBit(Key& k, int idx) {\n    if (idx < 64) k.lo |= (1ULL << idx);\n    else k.hi |= (1ULL << (idx - 64));\n}\nstatic inline void toggleBit(Key& k, int idx) {\n    if (idx < 64) k.lo ^= (1ULL << idx);\n    else k.hi ^= (1ULL << (idx - 64));\n}\n\nstatic inline Line buildLine(double theta, double u) {\n    // normal n=(cos, sin), direction t=(-sin, cos)\n    double cs = cos(theta), sn = sin(theta);\n    double tx = -sn, ty = cs;\n    double cx = u * cs, cy = u * sn;\n\n    long double px = (long double)cx + (long double)LEN * (long double)tx;\n    long double py = (long double)cy + (long double)LEN * (long double)ty;\n    long double qx = (long double)cx - (long double)LEN * (long double)tx;\n    long double qy = (long double)cy - (long double)LEN * (long double)ty;\n\n    Line L;\n    L.theta = theta;\n    L.u = u;\n    L.px = llround(px);\n    L.py = llround(py);\n    L.qx = llround(qx);\n    L.qy = llround(qy);\n    if (L.px == L.qx && L.py == L.qy) {\n        // extremely unlikely; force distinct\n        L.qx += 1;\n    }\n    return L;\n}\n\n// side test using exact integer cross product\n// returns 1 if cross>0, 0 if cross<0, -1 if cross==0 (strawberry disappears => invalid for us)\nstatic inline int sideBit(const Line& L, const Point& p) {\n    __int128 dx = (__int128)L.qx - (__int128)L.px;\n    __int128 dy = (__int128)L.qy - (__int128)L.py;\n    __int128 ax = (__int128)p.x - (__int128)L.px;\n    __int128 ay = (__int128)p.y - (__int128)L.py;\n    __int128 cr = dx * ay - dy * ax;\n    if (cr > 0) return 1;\n    if (cr < 0) return 0;\n    return -1;\n}\n\n// ---------------- State with incremental updates ----------------\nstruct State {\n    int N = 0;\n    int L = 0;\n    vector<Point> pts;\n    vector<Line> lines;\n\n    vector<Key> sig; // signature per point\n\n    boost::unordered_flat_map<Key, int, KeyHash> mp; // region signature -> count\n    array<int, 11> b{}; // b[d] = number of regions with exactly d strawberries, d=1..10\n    long long largeStrawberries = 0; // total strawberries in regions with >10\n    int largePieces = 0; // number of regions with >10\n\n    array<int, 11> a{}; // demand, 1..10\n\n    void clearCounts() {\n        mp.clear();\n        b.fill(0);\n        largeStrawberries = 0;\n        largePieces = 0;\n    }\n\n    inline void updateMetrics(int oldC, int newC) {\n        if (1 <= oldC && oldC <= 10) b[oldC]--;\n        if (1 <= newC && newC <= 10) b[newC]++;\n\n        if (oldC > 10) { largeStrawberries -= oldC; largePieces--; }\n        if (newC > 10) { largeStrawberries += newC; largePieces++; }\n    }\n\n    inline void incRegion(const Key& k) {\n        auto it = mp.find(k);\n        if (it == mp.end()) {\n            updateMetrics(0, 1);\n            mp.emplace(k, 1);\n        } else {\n            int oldC = it->second;\n            int newC = oldC + 1;\n            updateMetrics(oldC, newC);\n            it->second = newC;\n        }\n    }\n\n    inline void decRegion(const Key& k) {\n        auto it = mp.find(k);\n        // should exist\n        int oldC = it->second;\n        int newC = oldC - 1;\n        updateMetrics(oldC, newC);\n        if (newC == 0) mp.erase(it);\n        else it->second = newC;\n    }\n\n    inline int distributed() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], b[d]);\n        return s;\n    }\n\n    inline int overProduction() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) if (b[d] > a[d]) s += (b[d] - a[d]);\n        return s;\n    }\n\n    inline int energy() const {\n        // primary: maximize distributed()\n        // secondary: discourage too-large pieces (cnt>10) and overproduction (wasted)\n        int dist = distributed();\n        int over = overProduction();\n        // scaling chosen so 1 extra distributed dominates moderate penalties\n        long long E = (long long)dist * 10000LL - largeStrawberries * 2LL - (long long)over * 5LL;\n        if (E < (long long)INT_MIN) return INT_MIN;\n        if (E > (long long)INT_MAX) return INT_MAX;\n        return (int)E;\n    }\n\n    bool buildInitialSignatures() {\n        sig.assign(N, Key{0, 0});\n        clearCounts();\n        mp.reserve((size_t)N * 2 + 64);\n\n        for (int i = 0; i < L; i++) {\n            for (int j = 0; j < N; j++) {\n                int sb = sideBit(lines[i], pts[j]);\n                if (sb == -1) return false;\n                if (sb == 1) setBit(sig[j], i);\n            }\n        }\n        for (int j = 0; j < N; j++) incRegion(sig[j]);\n        return true;\n    }\n\n    // apply candidate replacement for one line index; updates signatures & counts incrementally\n    // if invalid (some strawberry on line), it rolls back partial changes and returns false\n    bool applyReplaceLine(int idx, const Line& newLine,\n                          vector<int>& changedIdx, vector<Key>& oldSig) {\n        changedIdx.clear();\n        oldSig.clear();\n        changedIdx.reserve(256);\n        oldSig.reserve(256);\n\n        for (int j = 0; j < N; j++) {\n            int nb = sideBit(newLine, pts[j]);\n            if (nb == -1) {\n                // rollback what we already changed\n                for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n                    int pj = changedIdx[t];\n                    Key os = oldSig[t];\n                    Key cs = sig[pj];\n                    decRegion(cs);\n                    incRegion(os);\n                    sig[pj] = os;\n                }\n                changedIdx.clear();\n                oldSig.clear();\n                return false;\n            }\n            int ob = getBit(sig[j], idx);\n            if (nb == ob) continue;\n\n            changedIdx.push_back(j);\n            oldSig.push_back(sig[j]);\n\n            Key ns = sig[j];\n            toggleBit(ns, idx);\n            decRegion(sig[j]);\n            incRegion(ns);\n            sig[j] = ns;\n        }\n        return true;\n    }\n\n    void rollbackReplaceLine(int idx, const vector<int>& changedIdx, const vector<Key>& oldSig) {\n        (void)idx;\n        for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n            int j = changedIdx[t];\n            Key os = oldSig[t];\n            Key cs = sig[j];\n            decRegion(cs);\n            incRegion(os);\n            sig[j] = os;\n        }\n    }\n};\n\n// ---------------- Timer ----------------\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// ---------------- Solver ----------------\nstatic inline double wrapTheta(double th) {\n    const double PI = acos(-1.0);\n    while (th < 0) th += PI;\n    while (th >= PI) th -= PI;\n    return th;\n}\n\nstatic Line randomLineNearPoints(RNG& rng, const vector<Point>& pts) {\n    const double PI = acos(-1.0);\n    double theta = rng.uniform(0.0, PI);\n    double cs = cos(theta), sn = sin(theta);\n\n    // anchor u near projection of a random point so the line is \"relevant\"\n    const Point& p = pts[rng.uniformInt(0, (int)pts.size() - 1)];\n    double proj = cs * (double)p.x + sn * (double)p.y;\n    double u = proj + rng.uniform(-800.0, 800.0);\n    // keep it intersecting the cake robustly\n    double lim = R * 0.95;\n    u = max(-lim, min(lim, u));\n\n    return buildLine(theta, u);\n}\n\nstatic bool lineHitsAnyPoint(const Line& L, const vector<Point>& pts) {\n    for (auto& p : pts) {\n        if (sideBit(L, p) == -1) return true;\n    }\n    return false;\n}\n\nstatic int chooseInitialL(int totalAttendees) {\n    // target regions somewhat larger than attendees (to allow empties)\n    double target = totalAttendees * 1.2;\n    // solve L(L+1)/2 + 1 >= target\n    double x = max(1.0, target - 1.0);\n    int L = (int)ceil((sqrt(1.0 + 8.0 * x) - 1.0) / 2.0);\n    L = max(4, min(100, L));\n    return L;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n    array<int, 11> a{};\n    for (int d = 1; d <= 10; d++) cin >> a[d];\n\n    vector<Point> pts(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    int totalAtt = 0;\n    for (int d = 1; d <= 10; d++) totalAtt += a[d];\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    int baseL = chooseInitialL(totalAtt);\n    vector<int> candL = {max(4, baseL - 5), baseL, min(100, baseL + 5)};\n    sort(candL.begin(), candL.end());\n    candL.erase(unique(candL.begin(), candL.end()), candL.end());\n\n    const double TIME_LIMIT = 2.85;\n\n    // global best\n    int bestDist = -1;\n    int bestEnergy = INT_MIN;\n    vector<Line> bestLines;\n\n    for (int ci = 0; ci < (int)candL.size(); ci++) {\n        double tNow = timer.elapsedSec();\n        if (tNow >= TIME_LIMIT) break;\n\n        double remaining = TIME_LIMIT - tNow;\n        double share = remaining / (double)(candL.size() - ci);\n\n        int L = candL[ci];\n\n        State st;\n        st.N = N;\n        st.L = L;\n        st.pts = pts;\n        st.a = a;\n        st.lines.resize(L);\n\n        // build initial random lines (avoid hitting any strawberry exactly)\n        for (int i = 0; i < L; i++) {\n            for (int tries = 0; tries < 1000; tries++) {\n                Line ln = randomLineNearPoints(rng, pts);\n                if (!lineHitsAnyPoint(ln, pts)) {\n                    st.lines[i] = ln;\n                    break;\n                }\n            }\n        }\n        if (!st.buildInitialSignatures()) {\n            // fallback: no cuts\n            cerr << \"initial build failed (rare)\\n\";\n            cout << 0 << \"\\n\";\n            return 0;\n        }\n\n        int curE = st.energy();\n        int curDist = st.distributed();\n\n        // best for this run\n        int runBestDist = curDist;\n        int runBestE = curE;\n        vector<Line> runBestLines = st.lines;\n\n        vector<int> changedIdx;\n        vector<Key> oldSig;\n\n        const double PI = acos(-1.0);\n        auto startTime = chrono::steady_clock::now();\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= share) break;\n\n            double progress = elapsed / share;\n            // temperature schedule\n            double T0 = 4000.0, T1 = 200.0;\n            double T = T0 * (1.0 - progress) + T1 * progress;\n\n            int idx = rng.uniformInt(0, L - 1);\n            Line oldLine = st.lines[idx];\n\n            Line cand = oldLine;\n            // mutation: sometimes resample, otherwise perturb\n            if (rng.uniform01() < 0.10) {\n                cand = randomLineNearPoints(rng, pts);\n            } else {\n                double angleScale = 0.60 * (1.0 - progress) + 0.02;\n                double uScale = 6000.0 * (1.0 - progress) + 250.0;\n\n                cand.theta = wrapTheta(cand.theta + rng.uniform(-angleScale, angleScale));\n                cand.u += rng.uniform(-uScale, uScale);\n                double lim = R * 0.98;\n                cand.u = max(-lim, min(lim, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            }\n\n            // try apply\n            int oldE = curE;\n            int oldD = curDist;\n\n            if (!st.applyReplaceLine(idx, cand, changedIdx, oldSig)) {\n                continue; // invalid candidate\n            }\n\n            int newE = st.energy();\n            int newD = st.distributed();\n            int delta = newE - oldE;\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double prob = exp((double)delta / T);\n                if (rng.uniform01() < prob) accept = true;\n            }\n\n            if (accept) {\n                st.lines[idx] = cand;\n                curE = newE;\n                curDist = newD;\n\n                if (curDist > runBestDist || (curDist == runBestDist && curE > runBestE)) {\n                    runBestDist = curDist;\n                    runBestE = curE;\n                    runBestLines = st.lines;\n                }\n            } else {\n                st.rollbackReplaceLine(idx, changedIdx, oldSig);\n                curE = oldE;\n                curDist = oldD;\n            }\n        }\n\n        if (runBestDist > bestDist || (runBestDist == bestDist && runBestE > bestEnergy)) {\n            bestDist = runBestDist;\n            bestEnergy = runBestE;\n            bestLines = runBestLines;\n        }\n    }\n\n    // output\n    if (bestLines.empty()) {\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n    cout << (int)bestLines.size() << \"\\n\";\n    for (auto& L : bestLines) {\n        cout << L.px << \" \" << L.py << \" \" << L.qx << \" \" << L.qy << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    explicit XorShift(uint64_t seed = 0) { x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline uint64_t maskRange64(int l, int r) {\n    // 0 <= l <= r < 64\n    // returns bits l..r set\n    uint64_t left = (~0ULL) << l;\n    uint64_t right = (r == 63) ? ~0ULL : ((1ULL << (r + 1)) - 1ULL);\n    return left & right;\n}\n\nstruct Bits128 {\n    uint64_t lo = 0, hi = 0; // bits [0..63], [64..127]\n\n    inline void set(int idx) {\n        if (idx < 64) lo |= 1ULL << idx;\n        else hi |= 1ULL << (idx - 64);\n    }\n    inline bool test(int idx) const {\n        if (idx < 64) return (lo >> idx) & 1ULL;\n        else return (hi >> (idx - 64)) & 1ULL;\n    }\n    inline void reset(int idx) {\n        if (idx < 64) lo &= ~(1ULL << idx);\n        else hi &= ~(1ULL << (idx - 64));\n    }\n    inline bool any() const { return lo || hi; }\n\n    inline Bits128 operator&(const Bits128& o) const { return Bits128{lo & o.lo, hi & o.hi}; }\n\n    inline bool anyInRange(int l, int r) const { // inclusive\n        if (l > r) return false;\n        uint64_t mlo = 0, mhi = 0;\n        if (l < 64) {\n            int rr = min(r, 63);\n            mlo = maskRange64(l, rr);\n        }\n        if (r >= 64) {\n            int ll = max(l, 64) - 64;\n            int rr = r - 64;\n            mhi = maskRange64(ll, rr);\n        }\n        return (lo & mlo) || (hi & mhi);\n    }\n};\n\nstruct Point { int x, y; };\n\nstruct Move {\n    Point p1, p2, p3, p4;\n    double val = -1e100;\n};\n\nstruct State {\n    int N;\n    int shiftV;\n    int U, V; // U=2N-1, V=2N-1 (for u=x+y, v=x-y+shiftV)\n    // dot occupancy\n    array<uint64_t, 61> dotRow{}; // bit x\n    array<uint64_t, 61> dotCol{}; // bit y\n\n    // dots on diagonals in (u,v)\n    vector<Bits128> diagVdots; // indexed by vIdx, contains bits of u\n    vector<Bits128> antiUdots; // indexed by u, contains bits of vIdx\n\n    // used axis segments\n    array<uint64_t, 61> hUsed{}; // per y, bits x=0..N-2 for segment (x,y)-(x+1,y)\n    array<uint64_t, 61> vUsed{}; // per x, bits y=0..N-2 for segment (x,y)-(x,y+1)\n\n    // used diagonal segments\n    // d1: slope +1 segments (x,y)-(x+1,y+1), size (N-1)*(N-1)\n    // d2: slope -1 segments (x,y+1)-(x+1,y), stored by (x,y) for y=0..N-2\n    vector<uint8_t> d1Used, d2Used;\n\n    long long sumW = 0; // sum of weights of dotted points\n\n    State(int N_=0): N(N_) {}\n\n    inline bool hasDot(int x, int y) const {\n        return (dotRow[y] >> x) & 1ULL;\n    }\n\n    inline void addDot(int x, int y) {\n        dotRow[y] |= 1ULL << x;\n        dotCol[x] |= 1ULL << y;\n        int u = x + y;\n        int vIdx = x - y + shiftV;\n        diagVdots[vIdx].set(u);\n        antiUdots[u].set(vIdx);\n    }\n\n    inline bool rowHasDotBetween(int y, int x1, int x2) const {\n        int l = min(x1, x2) + 1;\n        int r = max(x1, x2) - 1;\n        if (l > r) return false;\n        return (dotRow[y] & maskRange64(l, r)) != 0;\n    }\n    inline bool colHasDotBetween(int x, int y1, int y2) const {\n        int l = min(y1, y2) + 1;\n        int r = max(y1, y2) - 1;\n        if (l > r) return false;\n        return (dotCol[x] & maskRange64(l, r)) != 0;\n    }\n\n    inline uint64_t segMaskX(int x1, int x2) const {\n        int l = min(x1, x2);\n        int r = max(x1, x2) - 1;\n        if (l > r) return 0;\n        return maskRange64(l, r);\n    }\n    inline uint64_t segMaskY(int y1, int y2) const {\n        int l = min(y1, y2);\n        int r = max(y1, y2) - 1;\n        if (l > r) return 0;\n        return maskRange64(l, r);\n    }\n\n    inline bool canAxisRect(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 || y1 == y2) return false;\n        if (hasDot(x1, y1)) return false;\n        if (!hasDot(x2, y1) || !hasDot(x2, y2) || !hasDot(x1, y2)) return false;\n\n        // Condition 2 (no other dots on perimeter)\n        if (rowHasDotBetween(y1, x1, x2)) return false;\n        if (rowHasDotBetween(y2, x1, x2)) return false;\n        if (colHasDotBetween(x1, y1, y2)) return false;\n        if (colHasDotBetween(x2, y1, y2)) return false;\n\n        // Condition 3 (no shared axis segments)\n        uint64_t hm = segMaskX(x1, x2);\n        if ((hUsed[y1] & hm) || (hUsed[y2] & hm)) return false;\n        uint64_t vm = segMaskY(y1, y2);\n        if ((vUsed[x1] & vm) || (vUsed[x2] & vm)) return false;\n\n        return true;\n    }\n\n    inline void applyAxisRect(const Move& mv) {\n        int x1 = mv.p1.x, y1 = mv.p1.y;\n        int x2 = mv.p2.x, y2 = mv.p3.y; // mv.p2=(x2,y1), mv.p3=(x2,y2), mv.p4=(x1,y2)\n\n        // mark used segments\n        uint64_t hm = segMaskX(x1, x2);\n        hUsed[y1] |= hm;\n        hUsed[y2] |= hm;\n        uint64_t vm = segMaskY(y1, y2);\n        vUsed[x1] |= vm;\n        vUsed[x2] |= vm;\n\n        addDot(x1, y1);\n    }\n\n    // diagonal segment helpers\n    inline int idxD(int x, int y) const { // (N-1) x (N-1)\n        return x + (N - 1) * y;\n    }\n\n    bool diag1Free(const Point& a, const Point& b) const {\n        int dx = b.x - a.x, dy = b.y - a.y;\n        if (dx == 0) return true;\n        if (dx != dy) return false;\n        int step = (dx > 0) ? 1 : -1;\n        int len = abs(dx);\n        for (int i = 0; i < len; i++) {\n            int x = a.x + i * step;\n            int y = a.y + i * step;\n            int xx = (step == 1) ? x : x - 1;\n            int yy = (step == 1) ? y : y - 1;\n            if (xx < 0 || yy < 0 || xx >= N - 1 || yy >= N - 1) return false;\n            if (d1Used[idxD(xx, yy)]) return false;\n        }\n        return true;\n    }\n    void diag1Mark(const Point& a, const Point& b) {\n        int dx = b.x - a.x;\n        if (dx == 0) return;\n        int step = (dx > 0) ? 1 : -1;\n        int len = abs(dx);\n        for (int i = 0; i < len; i++) {\n            int x = a.x + i * step;\n            int y = a.y + i * step;\n            int xx = (step == 1) ? x : x - 1;\n            int yy = (step == 1) ? y : y - 1;\n            d1Used[idxD(xx, yy)] = 1;\n        }\n    }\n\n    bool diag2Free(const Point& a, const Point& b) const {\n        int dx = b.x - a.x, dy = b.y - a.y;\n        if (dx == 0) return true;\n        if (dx != -dy) return false;\n        int stepX = (dx > 0) ? 1 : -1;\n        int len = abs(dx);\n        for (int i = 0; i < len; i++) {\n            int x = a.x + i * stepX;\n            int y = a.y - i * stepX; // because dy = -dx\n            int xx, yy;\n            if (stepX == 1) {\n                // (x,y) -> (x+1,y-1) uses d2[x][y-1]\n                xx = x;\n                yy = y - 1;\n            } else {\n                // (x,y) -> (x-1,y+1) reverse of (x-1,y+1)->(x,y) uses d2[x-1][y]\n                xx = x - 1;\n                yy = y;\n            }\n            if (xx < 0 || yy < 0 || xx >= N - 1 || yy >= N - 1) return false;\n            if (d2Used[idxD(xx, yy)]) return false;\n        }\n        return true;\n    }\n    void diag2Mark(const Point& a, const Point& b) {\n        int dx = b.x - a.x;\n        if (dx == 0) return;\n        int stepX = (dx > 0) ? 1 : -1;\n        int len = abs(dx);\n        for (int i = 0; i < len; i++) {\n            int x = a.x + i * stepX;\n            int y = a.y - i * stepX;\n            int xx, yy;\n            if (stepX == 1) { xx = x; yy = y - 1; }\n            else { xx = x - 1; yy = y; }\n            d2Used[idxD(xx, yy)] = 1;\n        }\n    }\n\n    inline Point uvToXY(int u, int vIdx) const {\n        int v = vIdx - shiftV;\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    inline bool canDiagRect(int x1, int y1, int u2, int v2Idx) const {\n        // p1 = (x1,y1) is (u1,v1). other corners determined by (u2,v1), (u2,v2), (u1,v2)\n        if (hasDot(x1, y1)) return false;\n        int u1 = x1 + y1;\n        int v1Idx = x1 - y1 + shiftV;\n\n        // perimeter dot checks in (u,v) space:\n        // edges on v=v1 between u1-u2, v=v2 between u1-u2, u=u1 between v1-v2, u=u2 between v1-v2\n        if (diagVdots[v1Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (diagVdots[v2Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (antiUdots[u1].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n        if (antiUdots[u2].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n\n        // segment overlap checks (diagonal segments)\n        Point p1 = {x1, y1};\n        Point p2 = uvToXY(u2, v1Idx);\n        Point p3 = uvToXY(u2, v2Idx);\n        Point p4 = uvToXY(u1, v2Idx);\n\n        // sanity bounds\n        auto in = [&](Point p) { return 0 <= p.x && p.x < N && 0 <= p.y && p.y < N; };\n        if (!in(p2) || !in(p3) || !in(p4)) return false;\n        if (!hasDot(p2.x, p2.y) || !hasDot(p3.x, p3.y) || !hasDot(p4.x, p4.y)) return false;\n\n        // edges: p1-p2 (diag1), p2-p3 (diag2), p3-p4 (diag1), p4-p1 (diag2)\n        if (!diag1Free(p1, p2)) return false;\n        if (!diag2Free(p2, p3)) return false;\n        if (!diag1Free(p3, p4)) return false;\n        if (!diag2Free(p4, p1)) return false;\n\n        return true;\n    }\n\n    inline void applyDiagRect(const Move& mv) {\n        // mark segments\n        diag1Mark(mv.p1, mv.p2);\n        diag2Mark(mv.p2, mv.p3);\n        diag1Mark(mv.p3, mv.p4);\n        diag2Mark(mv.p4, mv.p1);\n\n        addDot(mv.p1.x, mv.p1.y);\n    }\n};\n\nstruct Params {\n    int topP = 200;     // how many high-weight empty points to try first\n    int midP = 700;     // fallback\n    int randP = 50;     // random empty samples\n    double alpha = 0.35;// perimeter penalty\n    double noise = 0.02;// small random noise for tie-breaking\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n\n    int c = (N - 1) / 2;\n    vector<vector<int>> w(N, vector<int>(N, 0));\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) {\n        int dx = x - c, dy = y - c;\n        w[x][y] = dx * dx + dy * dy + 1;\n    }\n\n    vector<Point> initial(M);\n    for (int i = 0; i < M; i++) cin >> initial[i].x >> initial[i].y;\n\n    // pre-sort points by descending weight\n    vector<Point> allPoints;\n    allPoints.reserve(N * N);\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) allPoints.push_back({x, y});\n    sort(allPoints.begin(), allPoints.end(), [&](const Point& a, const Point& b) {\n        int wa = w[a.x][a.y], wb = w[b.x][b.y];\n        if (wa != wb) return wa > wb;\n        if (a.x != b.x) return a.x < b.x;\n        return a.y < b.y;\n    });\n\n    auto start = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n    };\n\n    auto runOnce = [&](uint64_t seed, const Params& par) {\n        State st(N);\n        st.shiftV = N - 1;\n        st.U = 2 * N - 1;\n        st.V = 2 * N - 1;\n        st.diagVdots.assign(st.V, Bits128{});\n        st.antiUdots.assign(st.U, Bits128{});\n        st.d1Used.assign((N - 1) * (N - 1), 0);\n        st.d2Used.assign((N - 1) * (N - 1), 0);\n        st.sumW = 0;\n        for (auto &x : st.dotRow) x = 0;\n        for (auto &x : st.dotCol) x = 0;\n        for (auto &x : st.hUsed) x = 0;\n        for (auto &x : st.vUsed) x = 0;\n\n        for (auto p : initial) {\n            st.addDot(p.x, p.y);\n            st.sumW += w[p.x][p.y];\n        }\n\n        XorShift rng(seed);\n\n        vector<array<int, 8>> ops;\n        ops.reserve(N * N);\n\n        auto collectP1 = [&](int P) {\n            vector<Point> res;\n            res.reserve(P + par.randP);\n            for (const auto& p : allPoints) {\n                if ((int)res.size() >= P) break;\n                if (!st.hasDot(p.x, p.y)) res.push_back(p);\n            }\n            // random empties for exploration\n            for (int i = 0; i < par.randP; i++) {\n                for (int t = 0; t < 50; t++) {\n                    int x = rng.nextInt(0, N - 1);\n                    int y = rng.nextInt(0, N - 1);\n                    if (!st.hasDot(x, y)) {\n                        res.push_back({x, y});\n                        break;\n                    }\n                }\n            }\n            return res;\n        };\n\n        auto perimeterAxis = [&](int x1, int y1, int x2, int y2) -> int {\n            return 2 * (abs(x2 - x1) + abs(y2 - y1));\n        };\n        auto perimeterDiag = [&](const Point& p1, const Point& p2, const Point& p3, const Point& p4) -> int {\n            int a = abs(p2.x - p1.x);\n            int b = abs(p3.x - p2.x);\n            return 2 * (a + b);\n        };\n\n        auto findBestMove = [&](Move& best) -> bool {\n            best.val = -1e100;\n            bool found = false;\n\n            auto tryList = [&](int P) -> bool {\n                vector<Point> p1s = collectP1(P);\n                for (const auto& p1 : p1s) {\n                    int x1 = p1.x, y1 = p1.y;\n                    if (st.hasDot(x1, y1)) continue;\n\n                    // axis-aligned candidates\n                    uint64_t yMask = st.dotCol[x1];\n                    // (y1 bit should be 0 because empty, but harmless)\n                    while (yMask) {\n                        int y2 = __builtin_ctzll(yMask);\n                        yMask &= yMask - 1;\n                        if (y2 == y1) continue;\n\n                        uint64_t inter = st.dotRow[y1] & st.dotRow[y2];\n                        inter &= ~(1ULL << x1);\n                        while (inter) {\n                            int x2 = __builtin_ctzll(inter);\n                            inter &= inter - 1;\n                            if (x2 == x1) continue;\n\n                            if (!st.canAxisRect(x1, y1, x2, y2)) continue;\n\n                            Move mv;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = {x2, y1};\n                            mv.p3 = {x2, y2};\n                            mv.p4 = {x1, y2};\n\n                            int per = perimeterAxis(x1, y1, x2, y2);\n                            double val = (double)w[x1][y1] - par.alpha * per + par.noise * rng.nextDouble();\n                            if (val > best.val) {\n                                best = mv;\n                                best.val = val;\n                                found = true;\n                            }\n                        }\n                    }\n\n                    // 45-degree rotated candidates using (u,v)\n                    int u1 = x1 + y1;\n                    int v1Idx = x1 - y1 + st.shiftV;\n                    Bits128 vMask = st.antiUdots[u1]; // all v with dots on anti-diagonal u=u1\n                    // iterate v2\n                    uint64_t lo = vMask.lo, hi = vMask.hi;\n                    auto handleV2 = [&](int v2Idx) {\n                        if (v2Idx == v1Idx) return;\n                        Bits128 interU = st.diagVdots[v1Idx] & st.diagVdots[v2Idx];\n                        if (u1 < 128) interU.reset(u1);\n                        if (!interU.any()) return;\n\n                        uint64_t ulo = interU.lo, uhi = interU.hi;\n                        auto handleU2 = [&](int u2) {\n                            if (u2 == u1) return;\n                            if (!st.canDiagRect(x1, y1, u2, v2Idx)) return;\n\n                            int v = v2Idx - st.shiftV;\n                            (void)v;\n\n                            Point p2 = st.uvToXY(u2, v1Idx);\n                            Point p3 = st.uvToXY(u2, v2Idx);\n                            Point p4 = st.uvToXY(u1, v2Idx);\n\n                            Move mv;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = p2;\n                            mv.p3 = p3;\n                            mv.p4 = p4;\n\n                            int per = perimeterDiag(mv.p1, mv.p2, mv.p3, mv.p4);\n                            double val = (double)w[x1][y1] - par.alpha * per + par.noise * rng.nextDouble();\n                            if (val > best.val) {\n                                best = mv;\n                                best.val = val;\n                                found = true;\n                            }\n                        };\n\n                        while (ulo) {\n                            int b = __builtin_ctzll(ulo);\n                            ulo &= ulo - 1;\n                            handleU2(b);\n                        }\n                        while (uhi) {\n                            int b = __builtin_ctzll(uhi);\n                            uhi &= uhi - 1;\n                            handleU2(64 + b);\n                        }\n                    };\n\n                    while (lo) {\n                        int b = __builtin_ctzll(lo);\n                        lo &= lo - 1;\n                        handleV2(b);\n                    }\n                    while (hi) {\n                        int b = __builtin_ctzll(hi);\n                        hi &= hi - 1;\n                        handleV2(64 + b);\n                    }\n                }\n                return found;\n            };\n\n            if (tryList(par.topP)) return true;\n            if (tryList(par.midP)) return true;\n            // full scan fallback\n            if (tryList(N * N)) return true;\n            return false;\n        };\n\n        while (elapsedSec() < 4.90) {\n            Move best;\n            if (!findBestMove(best)) break;\n\n            // apply\n            if (best.p2.y == best.p1.y && best.p4.x == best.p1.x) {\n                // axis (as constructed)\n                st.applyAxisRect(best);\n            } else {\n                // diagonal\n                st.applyDiagRect(best);\n            }\n            st.sumW += w[best.p1.x][best.p1.y];\n\n            ops.push_back({best.p1.x, best.p1.y,\n                           best.p2.x, best.p2.y,\n                           best.p3.x, best.p3.y,\n                           best.p4.x, best.p4.y});\n        }\n\n        return ops;\n    };\n\n    // Multi-run with slightly different parameters (cheap)\n    vector<Params> plist;\n    {\n        Params p;\n        p.topP = 180; p.midP = 650; p.randP = 40; p.alpha = 0.32; p.noise = 0.015;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 240; p.midP = 900; p.randP = 60; p.alpha = 0.38; p.noise = 0.02;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 320; p.midP = 1200; p.randP = 70; p.alpha = 0.42; p.noise = 0.03;\n        plist.push_back(p);\n    }\n\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    vector<array<int, 8>> bestOps;\n    // Just choose the run with maximum number of operations as a proxy (usually correlates with score),\n    // since we don't compute full final score here (weights are monotone anyway).\n    for (int i = 0; i < (int)plist.size(); i++) {\n        if (elapsedSec() > 4.92) break;\n        auto ops = runOnce(baseSeed + 1234567ULL * i, plist[i]);\n        if (ops.size() > bestOps.size()) bestOps.swap(ops);\n    }\n\n    cout << bestOps.size() << \"\\n\";\n    for (auto &a : bestOps) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << a[i];\n        }\n        cout << \"\\n\";\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n};\n\nstatic constexpr int N = 10;\nstatic constexpr int M = 100;\n\nstruct Board {\n    // 0 empty, 1..3 flavors\n    array<uint8_t, M> a{};\n\n    inline uint8_t get(int r, int c) const { return a[r * N + c]; }\n    inline void set(int r, int c, uint8_t v) { a[r * N + c] = v; }\n\n    // dir: 0=F(up),1=B(down),2=L(left),3=R(right)\n    void tilt(int dir) {\n        if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = get(r, c);\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) set(r, c, (c < k ? tmp[c] : 0));\n            }\n        } else if (dir == 3) { // R\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = get(r, c);\n                    if (v) tmp[k++] = v;\n                }\n                // tmp[0..k-1] is from right to left; place preserving order towards right\n                for (int c = 0; c < N; c++) set(r, c, 0);\n                for (int i = 0; i < k; i++) set(r, N - 1 - i, tmp[i]);\n            }\n        } else if (dir == 0) { // F (up)\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = get(r, c);\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) set(r, c, (r < k ? tmp[r] : 0));\n            }\n        } else { // dir == 1, B (down)\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = get(r, c);\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) set(r, c, 0);\n                for (int i = 0; i < k; i++) set(N - 1 - i, c, tmp[i]);\n            }\n        }\n    }\n\n    void place_by_p(int p, uint8_t flavor) {\n        // p is 1-indexed among empty cells in row-major order.\n        int cnt = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                cnt++;\n                if (cnt == p) {\n                    a[i] = flavor;\n                    return;\n                }\n            }\n        }\n        // should never happen\n    }\n\n    void place_random_empty(uint8_t flavor, XorShift64 &rng) {\n        int empties = 0;\n        for (int i = 0; i < M; i++) empties += (a[i] == 0);\n        if (empties == 0) return;\n        int k = rng.next_int(empties);\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                if (k == 0) {\n                    a[i] = flavor;\n                    return;\n                }\n                --k;\n            }\n        }\n    }\n\n    // Heuristic correlated with true objective:\n    // - sum of squares of same-flavor connected components (strongly aligned with final score numerator)\n    // - plus small bonuses for same-flavor adjacencies and for clustering empties (keeps candies compact)\n    long long heuristic() const {\n        bool vis[M];\n        memset(vis, 0, sizeof(vis));\n\n        long long comp_sq_sum = 0;\n        int same_adj = 0;\n        int empty_adj = 0;\n\n        // adjacency counts (right, down)\n        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n            uint8_t v = get(r, c);\n            if (c + 1 < N) {\n                uint8_t u = get(r, c + 1);\n                if (v && u && v == u) same_adj++;\n                if (!v && !u) empty_adj++;\n            }\n            if (r + 1 < N) {\n                uint8_t u = get(r + 1, c);\n                if (v && u && v == u) same_adj++;\n                if (!v && !u) empty_adj++;\n            }\n        }\n\n        // BFS for component squares\n        int q[M];\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0 || vis[i]) continue;\n            uint8_t col = a[i];\n            int head = 0, tail = 0;\n            vis[i] = true;\n            q[tail++] = i;\n            int cnt = 0;\n            while (head < tail) {\n                int v = q[head++];\n                cnt++;\n                int r = v / N, c = v % N;\n                auto try_push = [&](int nr, int nc) {\n                    if (nr < 0 || nr >= N || nc < 0 || nc >= N) return;\n                    int ni = nr * N + nc;\n                    if (!vis[ni] && a[ni] == col) {\n                        vis[ni] = true;\n                        q[tail++] = ni;\n                    }\n                };\n                try_push(r - 1, c);\n                try_push(r + 1, c);\n                try_push(r, c - 1);\n                try_push(r, c + 1);\n            }\n            comp_sq_sum += 1LL * cnt * cnt;\n        }\n\n        // weights (tuned lightly; not critical)\n        // comp_sq_sum dominates, others help break ties / stabilize packing.\n        return comp_sq_sum * 1000LL + same_adj * 10LL + empty_adj;\n    }\n};\n\nstatic inline char dir_char(int d) {\n    if (d == 0) return 'F';\n    if (d == 1) return 'B';\n    if (d == 2) return 'L';\n    return 'R';\n}\n\nint greedy_best_dir(const Board &b) {\n    long long best = LLONG_MIN;\n    int bestd = 0;\n    for (int d = 0; d < 4; d++) {\n        Board nb = b;\n        nb.tilt(d);\n        long long h = nb.heuristic();\n        if (h > best) {\n            best = h;\n            bestd = d;\n        }\n    }\n    return bestd;\n}\n\nlong long rollout_value(Board b, int t_next, int depth, const array<uint8_t, 100> &flv, XorShift64 &rng) {\n    int t = t_next;\n    for (int step = 0; step < depth && t < 100; step++, t++) {\n        b.place_random_empty(flv[t], rng);\n        int d = greedy_best_dir(b);\n        b.tilt(d);\n    }\n    return b.heuristic();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    array<uint8_t, 100> flv{};\n    for (int i = 0; i < 100; i++) {\n        int x;\n        cin >> x;\n        flv[i] = (uint8_t)x;\n    }\n\n    Board cur;\n    // Seed RNG from flavor sequence (deterministic across runs)\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < 100; i++) seed = (seed ^ flv[i]) * 1099511628211ULL;\n    XorShift64 rng(seed);\n\n    auto t_start = chrono::steady_clock::now();\n    const double TL = 1.95; // a bit below 2.0s\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        cin >> p;\n        cur.place_by_p(p, flv[t]);\n\n        if (t == 99) {\n            // No need to output the last tilt.\n            break;\n        }\n\n        // Budget parameters (simple schedule + emergency shrink if time is tight)\n        int remain = 99 - t;\n        int depth = (remain >= 20 ? 4 : 3);\n        int K = (t < 25 ? 14 : (t < 60 ? 10 : (t < 85 ? 7 : 4)));\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n        double left = TL - elapsed;\n        if (left < 0.2) { depth = 2; K = 2; }\n        else if (left < 0.4) { depth = 3; K = min(K, 4); }\n\n        long long bestVal = LLONG_MIN;\n        int bestDir = 0;\n\n        // Evaluate all 4 possible tilts by Monte Carlo lookahead\n        for (int d0 = 0; d0 < 4; d0++) {\n            Board b0 = cur;\n            b0.tilt(d0);\n            long long baseH = b0.heuristic();\n\n            long long acc = 0;\n            // independent RNG streams per candidate to reduce bias\n            XorShift64 local_rng(rng.next_u64() ^ (uint64_t)(t * 131 + d0 * 977));\n\n            int useDepth = min(depth, 100 - (t + 1));\n            for (int k = 0; k < K; k++) {\n                acc += rollout_value(b0, t + 1, useDepth, flv, local_rng);\n            }\n\n            // Combine: immediate quality + expected near-future quality\n            // (scales are similar because all candidates simulate same depth)\n            long long val = baseH + acc / max(1, K);\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestDir = d0;\n            }\n        }\n\n        // Output and apply\n        char out = dir_char(bestDir);\n        cout << out << '\\n' << flush;\n        cur.tilt(bestDir);\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u64() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstatic vector<double> binom_pmf(int n, double p) {\n    vector<double> pmf(n+1, 0.0);\n    if (n == 0) { pmf[0] = 1.0; return pmf; }\n    if (p <= 0.0) { pmf[0] = 1.0; return pmf; }\n    if (p >= 1.0) { pmf[n] = 1.0; return pmf; }\n    double q = 1.0 - p;\n    pmf[0] = pow(q, n);\n    double ratio = p / q;\n    for (int k = 1; k <= n; k++) {\n        pmf[k] = pmf[k-1] * (double)(n - k + 1) / (double)k * ratio;\n    }\n    return pmf;\n}\n\nstatic int chooseN(int M, double eps) {\n    // Conservative mapping; bigger eps => bigger N\n    if (eps <= 0.05) return 25;\n    if (eps <= 0.10) return 35;\n    if (eps <= 0.20) return 50;\n    if (eps <= 0.30) return 75;\n    if (eps <= 0.35) return 90;\n    return 100;\n}\n\nstatic int ceil_log2_int(int x) {\n    int r = 0;\n    int v = 1;\n    while (v < x) { v <<= 1; r++; }\n    return r;\n}\n\nstatic string key_of(const vector<int>& v) {\n    string s;\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (i) s.push_back('-');\n        s += to_string(v[i]);\n    }\n    return s;\n}\n\nstatic double dist_L1(const vector<int>& a, const vector<int>& b) {\n    double d = 0;\n    for (int i = 0; i < (int)a.size(); i++) d += abs(a[i] - b[i]);\n    return d;\n}\n\n// Generate a random partition of N into B parts, each >= ms.\n// Optionally enforce strictly decreasing sizes (after sorting desc) if feasible.\nstatic bool gen_partition(int N, int B, int ms, bool enforce_unique_desc,\n                          SplitMix64& rng, vector<int>& out) {\n    int base = ms * B;\n    if (base > N) return false;\n    int rem = N - base;\n\n    vector<double> w(B);\n    double sumw = 0.0;\n    for (int i = 0; i < B; i++) {\n        w[i] = rng.next_double() + 1e-12;\n        sumw += w[i];\n    }\n\n    vector<int> add(B, 0);\n    vector<pair<double,int>> frac;\n    frac.reserve(B);\n    int sumAdd = 0;\n    for (int i = 0; i < B; i++) {\n        double x = rem * (w[i] / sumw);\n        int a = (int)floor(x);\n        add[i] = a;\n        sumAdd += a;\n        frac.push_back({x - a, i});\n    }\n    int left = rem - sumAdd;\n    sort(frac.begin(), frac.end(), [&](auto& p1, auto& p2){ return p1.first > p2.first; });\n    for (int t = 0; t < left; t++) add[frac[t].second]++;\n\n    out.assign(B, ms);\n    for (int i = 0; i < B; i++) out[i] += add[i];\n\n    sort(out.begin(), out.end(), greater<int>());\n\n    if (enforce_unique_desc) {\n        for (int i = 0; i+1 < B; i++) if (out[i] <= out[i+1]) return false;\n    }\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    int N = chooseN(M, eps);\n    int L = N * (N - 1) / 2;\n\n    // Decide minimum clique size (avoid too tiny blocks at high eps)\n    int ms;\n    if (eps <= 0.10) ms = 1;\n    else if (eps <= 0.20) ms = 2;\n    else if (eps <= 0.30) ms = 3;\n    else ms = 4;\n\n    // Decide number of blocks B\n    int targetSize;\n    if (eps <= 0.10) targetSize = 5;\n    else if (eps <= 0.20) targetSize = 7;\n    else if (eps <= 0.30) targetSize = 9;\n    else targetSize = 11;\n\n    int B0 = max(3, min(12, N / targetSize));\n    int B = max(B0, ceil_log2_int(M) + 1);\n    B = min(B, 12);\n    while (B >= 3 && B * ms > N) B--;\n    if (B < 3) B = 3;\n\n    // Can we enforce unique descending sizes?\n    // Need N >= B*ms + (B-1 + ... + 0) = B*ms + B*(B-1)/2\n    bool enforce_unique_desc = (N >= B * ms + B * (B - 1) / 2);\n\n    // Deterministic RNG seed from (M, eps)\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)M * 1000003ULL;\n    seed ^= (uint64_t)llround(eps * 1000.0) * 10007ULL;\n    SplitMix64 rng(seed);\n\n    // Precompute logP[s][d] for degree distribution given clique size s\n    vector<vector<double>> logP(N+1, vector<double>(N, -1e100));\n    for (int s = 1; s <= N; s++) {\n        int n1 = s - 1;\n        int n2 = N - s;\n        double p1 = 1.0 - eps;\n        double p2 = eps;\n        auto pmf1 = binom_pmf(n1, p1);\n        auto pmf2 = binom_pmf(n2, p2);\n        vector<double> conv(N, 0.0);\n        for (int a = 0; a <= n1; a++) {\n            double pa = pmf1[a];\n            if (pa == 0.0) continue;\n            for (int b = 0; b <= n2; b++) {\n                double pb = pmf2[b];\n                if (pb == 0.0) continue;\n                conv[a + b] += pa * pb;\n            }\n        }\n        for (int d = 0; d <= N-1; d++) {\n            double v = max(conv[d], 1e-300);\n            logP[s][d] = log(v);\n        }\n    }\n\n    // Build pool of candidate partitions\n    int poolTarget = 20000;\n    vector<vector<int>> pool;\n    pool.reserve(poolTarget);\n    unordered_set<string> seen;\n    seen.reserve(poolTarget * 2);\n\n    auto build_pool = [&](bool uniq) {\n        pool.clear();\n        seen.clear();\n        int tries = 0;\n        int maxTries = poolTarget * 20;\n        while ((int)pool.size() < poolTarget && tries < maxTries) {\n            tries++;\n            vector<int> part;\n            if (!gen_partition(N, B, ms, uniq, rng, part)) continue;\n            string k = key_of(part);\n            if (seen.insert(k).second) pool.push_back(std::move(part));\n        }\n    };\n\n    build_pool(enforce_unique_desc);\n    if ((int)pool.size() < max(M, 200)) {\n        // Relax uniqueness if too few\n        enforce_unique_desc = false;\n        build_pool(false);\n    }\n\n    // Farthest-point sampling to select M well-separated partitions\n    int P = (int)pool.size();\n    vector<int> chosenIdx;\n    chosenIdx.reserve(M);\n\n    // choose first: maximize spread (max-min)\n    int first = 0;\n    double bestSpread = -1;\n    for (int i = 0; i < P; i++) {\n        double spread = pool[i].front() - pool[i].back();\n        if (spread > bestSpread) { bestSpread = spread; first = i; }\n    }\n    chosenIdx.push_back(first);\n\n    vector<double> mind(P, 1e100);\n    vector<char> used(P, 0);\n    used[first] = 1;\n    for (int i = 0; i < P; i++) mind[i] = dist_L1(pool[i], pool[first]);\n\n    while ((int)chosenIdx.size() < M) {\n        int best = -1;\n        double bestVal = -1;\n        for (int i = 0; i < P; i++) {\n            if (used[i]) continue;\n            if (mind[i] > bestVal) { bestVal = mind[i]; best = i; }\n        }\n        if (best < 0) break;\n        used[best] = 1;\n        chosenIdx.push_back(best);\n        for (int i = 0; i < P; i++) {\n            if (used[i]) continue;\n            double d = dist_L1(pool[i], pool[best]);\n            if (d < mind[i]) mind[i] = d;\n        }\n    }\n\n    // If still short (unlikely), fill by random distinct from pool\n    for (int i = 0; (int)chosenIdx.size() < M && i < P; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            chosenIdx.push_back(i);\n        }\n    }\n\n    // Final codebook: clique size vectors\n    vector<vector<int>> codes(M);\n    for (int k = 0; k < M; k++) codes[k] = pool[chosenIdx[k]];\n\n    // Precompute original edge counts E_k\n    vector<int> Eorig(M, 0);\n    for (int k = 0; k < M; k++) {\n        long long E = 0;\n        for (int s : codes[k]) E += 1LL * s * (s - 1) / 2;\n        Eorig[k] = (int)E;\n    }\n\n    // Output graphs\n    cout << N << '\\n';\n    for (int k = 0; k < M; k++) {\n        const auto& part = codes[k];\n        vector<int> blk(N, -1);\n        int cur = 0;\n        for (int b = 0; b < (int)part.size(); b++) {\n            for (int t = 0; t < part[b]; t++) blk[cur++] = b;\n        }\n        string g;\n        g.reserve(L);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                g.push_back(blk[i] == blk[j] ? '1' : '0');\n            }\n        }\n        cout << g << '\\n';\n    }\n    cout.flush();\n\n    // Decode 100 queries\n    const double var_edges = (eps > 0.0 && eps < 1.0) ? (double)L * eps * (1.0 - eps) : 1.0;\n    const double wEdge = 0.10; // small auxiliary weight\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) break;\n\n        vector<int> deg(N, 0);\n        int m = 0;\n        int idx = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                char c = H[idx++];\n                if (c == '1') {\n                    deg[i]++; deg[j]++;\n                    m++;\n                }\n            }\n        }\n        sort(deg.begin(), deg.end(), greater<int>());\n\n        int bestK = 0;\n        double bestScore = -1e300;\n\n        for (int k = 0; k < M; k++) {\n            const auto& part = codes[k];\n            double sc = 0.0;\n            int pos = 0;\n            for (int s : part) {\n                for (int t = 0; t < s; t++) {\n                    int d = deg[pos++];\n                    sc += logP[s][d];\n                }\n            }\n\n            if (eps > 0.0 && eps < 1.0) {\n                double mu = eps * (double)L + (1.0 - 2.0 * eps) * (double)Eorig[k];\n                double z = (m - mu);\n                sc += wEdge * (-0.5 * (z * z) / var_edges);\n            }\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestK = k;\n            }\n        }\n\n        cout << bestK << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline long long comb2(long long c) { return c * (c - 1) / 2; }\n\n// Morton key for 0..2047 (11 bits)\nstatic inline uint64_t morton11(uint32_t x, uint32_t y) {\n    uint64_t key = 0;\n    for (int b = 0; b < 11; b++) {\n        key |= (uint64_t)((x >> b) & 1u) << (2 * b);\n        key |= (uint64_t)((y >> b) & 1u) << (2 * b + 1);\n    }\n    return key;\n}\n\nstruct Edge {\n    int u, v;\n    long long w;\n    uint64_t key;\n    int prefDay;\n    long double imp; // scaled to [0,1]\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, D, K;\n    cin >> N >> M >> D >> K;\n\n    vector<Edge> edges(M);\n    vector<long long> W(M);\n    vector<vector<pair<int,int>>> g(N); // (to, edgeId)\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i].u = u;\n        edges[i].v = v;\n        edges[i].w = w;\n        W[i] = w;\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    vector<int> X(N), Y(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n    // ---- Build a DFS spanning tree for LCA and 2-edge-cut detection ----\n    vector<int> parent(N, -1), parentEdge(N, -1), depth(N, 0);\n    vector<int> tin(N, -1), tout(N, -1), order;\n    vector<char> vis(N, 0), isTreeEdge(M, 0);\n    int timer = 0;\n\n    function<void(int)> dfs = [&](int v) {\n        vis[v] = 1;\n        tin[v] = timer++;\n        order.push_back(v);\n        for (auto [to, eid] : g[v]) {\n            if (to == parent[v]) continue;\n            if (!vis[to]) {\n                parent[to] = v;\n                parentEdge[to] = eid;\n                depth[to] = depth[v] + 1;\n                isTreeEdge[eid] = 1;\n                dfs(to);\n            }\n        }\n        tout[v] = timer++;\n    };\n\n    int root = 0;\n    dfs(root);\n\n    // Binary lifting for LCA\n    int LOG = 1;\n    while ((1 << LOG) <= N) LOG++;\n    vector<vector<int>> up(LOG, vector<int>(N, -1));\n    for (int i = 0; i < N; i++) up[0][i] = parent[i];\n    for (int k = 1; k < LOG; k++) {\n        for (int i = 0; i < N; i++) {\n            int p = up[k-1][i];\n            up[k][i] = (p == -1 ? -1 : up[k-1][p]);\n        }\n    }\n\n    auto is_ancestor = [&](int a, int b) -> bool {\n        return tin[a] <= tin[b] && tout[b] <= tout[a];\n    };\n\n    auto lca = [&](int a, int b) -> int {\n        if (a == -1 || b == -1) return -1;\n        if (is_ancestor(a, b)) return a;\n        if (is_ancestor(b, a)) return b;\n        int v = a;\n        for (int k = LOG - 1; k >= 0; k--) {\n            int p = up[k][v];\n            if (p != -1 && !is_ancestor(p, b)) v = p;\n        }\n        return parent[v];\n    };\n\n    // ---- Detect many 2-edge-cuts of size 2: (tree edge, unique crossing non-tree edge) ----\n    vector<long long> cntDelta(N, 0), cntSub(N, 0);\n    vector<int> xorDelta(N, 0), xorSub(N, 0);\n\n    for (int eid = 0; eid < M; eid++) {\n        if (isTreeEdge[eid]) continue;\n        int u = edges[eid].u;\n        int v = edges[eid].v;\n        int L = lca(u, v);\n\n        // count crossing edges using standard -2 at L\n        cntDelta[u] += 1;\n        cntDelta[v] += 1;\n        cntDelta[L] -= 2;\n\n        // xor of crossing edges for each subtree cut: just toggle endpoints\n        xorDelta[u] ^= eid;\n        xorDelta[v] ^= eid;\n    }\n\n    for (int i = 0; i < N; i++) {\n        cntSub[i] = cntDelta[i];\n        xorSub[i] = xorDelta[i];\n    }\n\n    // postorder accumulation using reverse of DFS order (works since parent discovered before children)\n    for (int idx = (int)order.size() - 1; idx >= 1; idx--) {\n        int v = order[idx];\n        int p = parent[v];\n        cntSub[p] += cntSub[v];\n        xorSub[p] ^= xorSub[v];\n    }\n\n    vector<vector<int>> conflict(M);\n    vector<pair<int,int>> conflictPairs;\n    for (int v = 1; v < N; v++) {\n        long long cover = cntSub[v];\n        if (cover == 1) {\n            int eTree = parentEdge[v];\n            int eNonTree = xorSub[v];\n            if (eTree >= 0 && eNonTree >= 0 && eTree != eNonTree) {\n                conflict[eTree].push_back(eNonTree);\n                conflict[eNonTree].push_back(eTree);\n                if (eTree < eNonTree) conflictPairs.push_back({eTree, eNonTree});\n                else conflictPairs.push_back({eNonTree, eTree});\n            }\n        }\n    }\n    for (int i = 0; i < M; i++) {\n        auto &c = conflict[i];\n        sort(c.begin(), c.end());\n        c.erase(unique(c.begin(), c.end()), c.end());\n    }\n    sort(conflictPairs.begin(), conflictPairs.end());\n    conflictPairs.erase(unique(conflictPairs.begin(), conflictPairs.end()), conflictPairs.end());\n\n    // ---- Edge importance estimation via sampled shortest path trees ----\n    long double meanW = 0;\n    for (auto &e : edges) meanW += (long double)e.w;\n    meanW /= max(1, M);\n\n    // select sources by farthest point sampling in coordinate space\n    int S = min(60, N);\n    vector<int> sources;\n    sources.reserve(S);\n    vector<long long> bestDist2(N, (1LL<<62));\n    int first = 0;\n    sources.push_back(first);\n    bestDist2[first] = 0;\n\n    for (int it = 1; it < S; it++) {\n        int last = sources.back();\n        for (int v = 0; v < N; v++) {\n            long long dx = X[v] - X[last];\n            long long dy = Y[v] - Y[last];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 < bestDist2[v]) bestDist2[v] = d2;\n        }\n        int farV = 0;\n        for (int v = 1; v < N; v++) if (bestDist2[v] > bestDist2[farV]) farV = v;\n        sources.push_back(farV);\n    }\n\n    vector<long double> rawImp(M, 0.0L);\n    const long long INF = (1LL<<62);\n\n    vector<long long> dist(N);\n    vector<int> parV(N), parE(N);\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int s : sources) {\n        // Dijkstra\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dist[s] = 0;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dist[v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parV[to] = v;\n                    parE[to] = eid;\n                    pq.push({nd, to});\n                } else if (nd == dist[to]) {\n                    // tie-breaker to stabilize: smaller edge id\n                    if (parE[to] == -1 || eid < parE[to]) {\n                        parV[to] = v;\n                        parE[to] = eid;\n                    }\n                }\n            }\n        }\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n\n        vector<int> sub(N, 1);\n        for (int v : ord) {\n            int p = parV[v];\n            if (p != -1) sub[p] += sub[v];\n        }\n\n        for (int v = 0; v < N; v++) {\n            int eid = parE[v];\n            if (eid == -1) continue;\n            long double factor = 1.0L + (long double)W[eid] / meanW;\n            rawImp[eid] += (long double)sub[v] * factor;\n        }\n    }\n\n    long double maxRaw = 1e-18L;\n    for (int i = 0; i < M; i++) maxRaw = max(maxRaw, rawImp[i]);\n    for (int i = 0; i < M; i++) edges[i].imp = rawImp[i] / maxRaw;\n\n    // ---- Initial spatial partition by Morton order of edge midpoint ----\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    for (int i = 0; i < M; i++) {\n        // midpoint sums: 0..2000 => fit in 11 bits\n        uint32_t mx = (uint32_t)(X[edges[i].u] + X[edges[i].v]);\n        uint32_t my = (uint32_t)(Y[edges[i].u] + Y[edges[i].v]);\n        edges[i].key = morton11(mx, my);\n    }\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        return edges[a].key < edges[b].key;\n    });\n\n    vector<int> dayOfEdge(M, 0);\n    int base = M / D, rem = M % D;\n    vector<int> target(D, base);\n    for (int d = 0; d < rem; d++) target[d]++;\n\n    int cur = 0;\n    for (int d = 0; d < D; d++) {\n        for (int t = 0; t < target[d]; t++) {\n            int eid = idx[cur++];\n            dayOfEdge[eid] = d;\n        }\n    }\n    // preference = initial day\n    for (int i = 0; i < M; i++) edges[i].prefDay = dayOfEdge[i];\n\n    // Build day lists + positions for fast move\n    vector<vector<int>> inDay(D);\n    vector<int> posInDay(M, -1);\n    auto rebuildDayLists = [&]() {\n        for (int d = 0; d < D; d++) inDay[d].clear();\n        for (int e = 0; e < M; e++) {\n            int d = dayOfEdge[e];\n            posInDay[e] = (int)inDay[d].size();\n            inDay[d].push_back(e);\n        }\n    };\n    rebuildDayLists();\n\n    auto applyMoveOnlyLists = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        // remove from old\n        int p = posInDay[e];\n        int last = inDay[od].back();\n        inDay[od][p] = last;\n        posInDay[last] = p;\n        inDay[od].pop_back();\n        // add to new\n        posInDay[e] = (int)inDay[nd].size();\n        inDay[nd].push_back(e);\n        dayOfEdge[e] = nd;\n    };\n\n    auto canPlaceEdgeInDay = [&](int e, int d) -> bool {\n        for (int p : conflict[e]) {\n            if (dayOfEdge[p] == d) return false;\n        }\n        return true;\n    };\n\n    // ---- Fix conflicts greedily using slack in K ----\n    for (auto [a, b] : conflictPairs) {\n        if (dayOfEdge[a] != dayOfEdge[b]) continue;\n        int badDay = dayOfEdge[a];\n\n        bool fixed = false;\n        // try moving b first\n        for (int nd = 0; nd < D; nd++) {\n            if (nd == badDay) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceEdgeInDay(b, nd)) continue;\n            applyMoveOnlyLists(b, nd);\n            fixed = true;\n            break;\n        }\n        if (!fixed) {\n            // try moving a\n            for (int nd = 0; nd < D; nd++) {\n                if (nd == badDay) continue;\n                if ((int)inDay[nd].size() >= K) continue;\n                if (!canPlaceEdgeInDay(a, nd)) continue;\n                applyMoveOnlyLists(a, nd);\n                fixed = true;\n                break;\n            }\n        }\n        // if still not fixed, leave it; SA will likely resolve later (rare).\n    }\n\n    // ---- Rebuild day lists to be safe ----\n    rebuildDayLists();\n\n    // ---- Stats for SA cost ----\n    // Cost = A*sum_d(sumImp[d]^2) + PV*sum_{d,v} C(cnt[d][v],2) + B*misCount\n    const long double A = 1.0L;\n    const long double PV = 5.0L;\n    const long double B = 0.02L;\n\n    vector<long double> sumImp(D, 0.0L);\n    vector<vector<int>> inc(D, vector<int>(N, 0));\n    vector<long long> dayPairs(D, 0);\n    long long misCount = 0;\n\n    auto rebuildStats = [&]() {\n        fill(sumImp.begin(), sumImp.end(), 0.0L);\n        for (int d = 0; d < D; d++) fill(inc[d].begin(), inc[d].end(), 0);\n        fill(dayPairs.begin(), dayPairs.end(), 0LL);\n        misCount = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = dayOfEdge[e];\n            sumImp[d] += edges[e].imp;\n            if (dayOfEdge[e] != edges[e].prefDay) misCount++;\n            int u = edges[e].u, v = edges[e].v;\n            inc[d][u]++; inc[d][v]++;\n        }\n        for (int d = 0; d < D; d++) {\n            long long pairs = 0;\n            for (int v = 0; v < N; v++) pairs += comb2(inc[d][v]);\n            dayPairs[d] = pairs;\n        }\n    };\n    rebuildStats();\n\n    auto computeCost = [&]() -> long double {\n        long double s = 0;\n        for (int d = 0; d < D; d++) s += sumImp[d] * sumImp[d];\n        long double p = 0;\n        for (int d = 0; d < D; d++) p += (long double)dayPairs[d];\n        return A * s + PV * p + B * (long double)misCount;\n    };\n\n    long double curCost = computeCost();\n\n    auto hardCheckSwap = [&](int e1, int e2, int d1, int d2) -> bool {\n        // after swap: e1->d2, e2->d1\n        auto newDay = [&](int e)->int {\n            if (e == e1) return d2;\n            if (e == e2) return d1;\n            return dayOfEdge[e];\n        };\n        for (int p : conflict[e1]) if (newDay(p) == d2) return false;\n        for (int p : conflict[e2]) if (newDay(p) == d1) return false;\n        return true;\n    };\n\n    auto hardCheckMove = [&](int e, int nd) -> bool {\n        if ((int)inDay[nd].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == nd) return false;\n        return true;\n    };\n\n    auto applyMoveWithStats = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n\n        // update cost parts: sumImp^2\n        long double sa = sumImp[od], sb = sumImp[nd];\n        long double imp = edges[e].imp;\n        long double deltaImpSq = (sa - imp) * (sa - imp) + (sb + imp) * (sb + imp) - sa * sa - sb * sb;\n\n        // mis\n        long long oldMis = (od != edges[e].prefDay);\n        long long newMis = (nd != edges[e].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // vertex pairs delta (two vertices, two days)\n        int u = edges[e].u, v = edges[e].v;\n        long long deltaPairs = 0;\n\n        auto updOne = [&](int day, int vert, int dc) {\n            int oldc = inc[day][vert];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        };\n        updOne(od, u, -1); updOne(od, v, -1);\n        updOne(nd, u, +1); updOne(nd, v, +1);\n\n        // apply to stats\n        curCost += A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp[od] -= imp;\n        sumImp[nd] += imp;\n        misCount += deltaMis;\n\n        // apply incidence and dayPairs\n        auto applyInc = [&](int day, int vert, int dc) {\n            dayPairs[day] -= comb2(inc[day][vert]);\n            inc[day][vert] += dc;\n            dayPairs[day] += comb2(inc[day][vert]);\n        };\n        applyInc(od, u, -1); applyInc(od, v, -1);\n        applyInc(nd, u, +1); applyInc(nd, v, +1);\n\n        // apply to day lists\n        applyMoveOnlyLists(e, nd);\n    };\n\n    auto applySwapWithStats = [&](int e1, int e2) {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        if (d1 == d2) return;\n\n        // sumImp^2 delta\n        long double s1 = sumImp[d1], s2 = sumImp[d2];\n        long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n        long double ns1 = s1 - i1 + i2;\n        long double ns2 = s2 - i2 + i1;\n        long double deltaImpSq = ns1*ns1 + ns2*ns2 - s1*s1 - s2*s2;\n\n        // mis delta\n        long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n        long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // vertex pair delta: handle up to 8 (day,vertex) updates, merge by brute force\n        struct Mod { int day, v, dc; };\n        vector<Mod> mods;\n        mods.reserve(8);\n        auto addMod = [&](int day, int v, int dc){ mods.push_back({day, v, dc}); };\n        addMod(d1, edges[e1].u, -1); addMod(d1, edges[e1].v, -1);\n        addMod(d2, edges[e1].u, +1); addMod(d2, edges[e1].v, +1);\n        addMod(d2, edges[e2].u, -1); addMod(d2, edges[e2].v, -1);\n        addMod(d1, edges[e2].u, +1); addMod(d1, edges[e2].v, +1);\n\n        // merge duplicates\n        long long deltaPairs = 0;\n        for (int i = 0; i < (int)mods.size(); i++) {\n            int day = mods[i].day, v = mods[i].v;\n            int dc = mods[i].dc;\n            for (int j = i+1; j < (int)mods.size(); j++) {\n                if (mods[j].day == day && mods[j].v == v) {\n                    dc += mods[j].dc;\n                    mods[j].dc = 0;\n                }\n            }\n            if (dc == 0) continue;\n            int oldc = inc[day][v];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        }\n\n        // apply\n        curCost += A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp[d1] = ns1;\n        sumImp[d2] = ns2;\n        misCount += deltaMis;\n\n        auto applyInc = [&](int day, int v, int dc) {\n            dayPairs[day] -= comb2(inc[day][v]);\n            inc[day][v] += dc;\n            dayPairs[day] += comb2(inc[day][v]);\n        };\n\n        // apply all mods again (without merge) because applyInc already handles incremental correctly\n        applyInc(d1, edges[e1].u, -1); applyInc(d1, edges[e1].v, -1);\n        applyInc(d2, edges[e1].u, +1); applyInc(d2, edges[e1].v, +1);\n        applyInc(d2, edges[e2].u, -1); applyInc(d2, edges[e2].v, -1);\n        applyInc(d1, edges[e2].u, +1); applyInc(d1, edges[e2].v, +1);\n\n        // swap in lists\n        applyMoveOnlyLists(e1, d2);\n        applyMoveOnlyLists(e2, d1);\n    };\n\n    // ---- Simulated annealing ----\n    XorShift64 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 5.8;\n\n    int iters = 0;\n    while (true) {\n        iters++;\n        if ((iters & 2047) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed > TIME_LIMIT) break;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = elapsed / TIME_LIMIT;\n        double T = 5.0 * (1.0 - t) + 0.05 * t; // cooling\n\n        int op = rng.nextInt(100);\n        if (op < 75) {\n            // swap\n            int e1 = rng.nextInt(M);\n            int e2 = rng.nextInt(M);\n            if (e1 == e2) continue;\n            int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n            if (d1 == d2) continue;\n            if (!hardCheckSwap(e1, e2, d1, d2)) continue;\n\n            // compute delta by simulating cost difference (cheaply) using current stats\n            long double oldC = curCost;\n\n            // compute prospective delta (repeat same calculations as applySwapWithStats, but without applying)\n            long double s1 = sumImp[d1], s2 = sumImp[d2];\n            long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n            long double ns1 = s1 - i1 + i2;\n            long double ns2 = s2 - i2 + i1;\n            long double deltaImpSq = ns1*ns1 + ns2*ns2 - s1*s1 - s2*s2;\n\n            long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n            long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            // vertex pair delta (same mod merge trick)\n            struct Mod { int day, v, dc; };\n            array<Mod,8> mods = {{\n                {d1, edges[e1].u, -1}, {d1, edges[e1].v, -1},\n                {d2, edges[e1].u, +1}, {d2, edges[e1].v, +1},\n                {d2, edges[e2].u, -1}, {d2, edges[e2].v, -1},\n                {d1, edges[e2].u, +1}, {d1, edges[e2].v, +1},\n            }};\n            long long deltaPairs = 0;\n            for (int i = 0; i < 8; i++) {\n                int day = mods[i].day, v = mods[i].v;\n                int dc = mods[i].dc;\n                if (dc == 0) continue;\n                for (int j = i+1; j < 8; j++) {\n                    if (mods[j].day == day && mods[j].v == v) {\n                        dc += mods[j].dc;\n                        mods[j].dc = 0;\n                    }\n                }\n                int oldc = inc[day][v];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            }\n\n            long double delta = A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(-(double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) {\n                applySwapWithStats(e1, e2);\n            } else {\n                curCost = oldC;\n            }\n        } else {\n            // move\n            int e = rng.nextInt(M);\n            int od = dayOfEdge[e];\n            int nd = rng.nextInt(D);\n            if (nd == od) continue;\n            if (!hardCheckMove(e, nd)) continue;\n\n            // prospective delta\n            long double sa = sumImp[od], sb = sumImp[nd];\n            long double imp = edges[e].imp;\n            long double deltaImpSq = (sa - imp) * (sa - imp) + (sb + imp) * (sb + imp) - sa * sa - sb * sb;\n\n            long long oldMis = (od != edges[e].prefDay);\n            long long newMis = (nd != edges[e].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            int u = edges[e].u, v = edges[e].v;\n            long long deltaPairs = 0;\n            auto updOne = [&](int day, int vert, int dc) {\n                int oldc = inc[day][vert];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            };\n            updOne(od, u, -1); updOne(od, v, -1);\n            updOne(nd, u, +1); updOne(nd, v, +1);\n\n            long double delta = A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(-(double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) applyMoveWithStats(e, nd);\n        }\n    }\n\n    // Final safety: ensure capacity <= K (should already hold)\n    // If any day exceeds K, move random edges out.\n    for (int d = 0; d < D; d++) {\n        while ((int)inDay[d].size() > K) {\n            int e = inDay[d].back();\n            bool moved = false;\n            for (int nd = 0; nd < D; nd++) {\n                if (nd == d) continue;\n                if ((int)inDay[nd].size() >= K) continue;\n                if (!canPlaceEdgeInDay(e, nd)) continue;\n                applyMoveOnlyLists(e, nd);\n                moved = true;\n                break;\n            }\n            if (!moved) break; // extremely unlikely\n        }\n    }\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (dayOfEdge[i] + 1);\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y, z;   // start coordinate\n    int axis;      // 0:x, 1:y, 2:z\n    int len;\n    int used = 0;  // how many already cut from the start\n};\n\nstruct Piece {\n    int segId;\n    int off;   // offset from segment start\n    int len;\n};\n\nstruct Plan {\n    int s0, s1;       // construction types for obj0/obj1\n    int a0, a1;       // axis for obj0/obj1\n    long double eval; // abs(vol diff) + sum(1/len shared)\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstatic long long volume_of(const vector<uint8_t>& occ) {\n    long long v = 0;\n    for (auto c : occ) v += (c != 0);\n    return v;\n}\n\n// Extract maximal consecutive occupied segments along an axis.\nstatic vector<Segment> extract_segments(int D, const vector<uint8_t>& occ, int axis) {\n    vector<Segment> segs;\n    if (axis == 0) { // along x, fixed (y,z)\n        for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int x = 0;\n            while (x < D) {\n                if (!occ[idx3(D, x, y, z)]) { x++; continue; }\n                int xs = x;\n                while (x < D && occ[idx3(D, x, y, z)]) x++;\n                int len = x - xs;\n                segs.push_back(Segment{xs, y, z, axis, len, 0});\n            }\n        }\n    } else if (axis == 1) { // along y, fixed (x,z)\n        for (int x = 0; x < D; x++) for (int z = 0; z < D; z++) {\n            int y = 0;\n            while (y < D) {\n                if (!occ[idx3(D, x, y, z)]) { y++; continue; }\n                int ys = y;\n                while (y < D && occ[idx3(D, x, y, z)]) y++;\n                int len = y - ys;\n                segs.push_back(Segment{x, ys, z, axis, len, 0});\n            }\n        }\n    } else { // axis==2 along z, fixed (x,y)\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                if (!occ[idx3(D, x, y, z)]) { z++; continue; }\n                int zs = z;\n                while (z < D && occ[idx3(D, x, y, z)]) z++;\n                int len = z - zs;\n                segs.push_back(Segment{x, y, zs, axis, len, 0});\n            }\n        }\n    }\n    return segs;\n}\n\nstruct PQItem {\n    int rem;\n    int id;\n};\nstruct PQComp {\n    bool operator()(const PQItem& a, const PQItem& b) const {\n        if (a.rem != b.rem) return a.rem < b.rem; // max-heap by rem\n        return a.id > b.id; // tie: smaller id first\n    }\n};\n\n// Simulate greedy pairing using only segment lengths, return sum(1/L) for shared blocks.\nstatic long double simulate_penalty(int D, const vector<int>& lensA, const vector<int>& lensB) {\n    vector<int> remA = lensA, remB = lensB;\n    priority_queue<PQItem, vector<PQItem>, PQComp> pqA, pqB;\n    for (int i = 0; i < (int)remA.size(); i++) if (remA[i] > 0) pqA.push({remA[i], i});\n    for (int i = 0; i < (int)remB.size(); i++) if (remB[i] > 0) pqB.push({remB[i], i});\n\n    long double pen = 0.0L;\n    for (int L = D; L >= 1; L--) {\n        while (!pqA.empty() && !pqB.empty() && pqA.top().rem >= L && pqB.top().rem >= L) {\n            auto a = pqA.top(); pqA.pop();\n            auto b = pqB.top(); pqB.pop();\n            remA[a.id] -= L;\n            remB[b.id] -= L;\n            pen += 1.0L / (long double)L;\n            if (remA[a.id] > 0) pqA.push({remA[a.id], a.id});\n            if (remB[b.id] > 0) pqB.push({remB[b.id], b.id});\n        }\n    }\n    return pen;\n}\n\n// DP to choose a stable representative per z (maximize number of times staying same between z and z-1).\nstatic vector<int> choose_stable_sequence(const vector<vector<int>>& opts) {\n    int D = (int)opts.size();\n    vector<vector<int>> par(D);\n    vector<long long> dp_prev, dp_cur;\n\n    dp_prev.assign(opts[0].size(), 0);\n    par[0].assign(opts[0].size(), -1);\n\n    for (int z = 1; z < D; z++) {\n        dp_cur.assign(opts[z].size(), LLONG_MIN / 4);\n        par[z].assign(opts[z].size(), -1);\n        for (int j = 0; j < (int)opts[z].size(); j++) {\n            for (int p = 0; p < (int)opts[z-1].size(); p++) {\n                long long cand = dp_prev[p] + (opts[z][j] == opts[z-1][p] ? 1 : 0);\n                if (cand > dp_cur[j]) {\n                    dp_cur[j] = cand;\n                    par[z][j] = p;\n                }\n            }\n        }\n        dp_prev.swap(dp_cur);\n    }\n\n    int bestj = 0;\n    for (int j = 1; j < (int)dp_prev.size(); j++) if (dp_prev[j] > dp_prev[bestj]) bestj = j;\n\n    vector<int> seq(D);\n    int cur = bestj;\n    for (int z = D-1; z >= 0; z--) {\n        seq[z] = opts[z][cur];\n        cur = par[z][cur];\n        if (z == 0) break;\n    }\n    return seq;\n}\n\n// Construction types:\n// 0: dense AND\n// 1: star per slice (stable hubs)\n// 2: min edge-cover per slice\nstatic vector<uint8_t> build_occ(int D,\n                                 const vector<string>& f,\n                                 const vector<string>& r,\n                                 int type) {\n    vector<vector<int>> X(D), Y(D);\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) if (f[z][x] == '1') X[z].push_back(x);\n        for (int y = 0; y < D; y++) if (r[z][y] == '1') Y[z].push_back(y);\n        // guaranteed non-empty by statement\n    }\n\n    vector<uint8_t> occ(D * D * D, 0);\n\n    if (type == 0) {\n        for (int z = 0; z < D; z++)\n            for (int x : X[z])\n                for (int y : Y[z])\n                    occ[idx3(D, x, y, z)] = 1;\n    } else if (type == 1) {\n        vector<int> x0 = choose_stable_sequence(X);\n        vector<int> y0 = choose_stable_sequence(Y);\n        for (int z = 0; z < D; z++) {\n            for (int x : X[z]) occ[idx3(D, x, y0[z], z)] = 1;\n            for (int y : Y[z]) occ[idx3(D, x0[z], y, z)] = 1;\n        }\n    } else {\n        for (int z = 0; z < D; z++) {\n            auto &xs = X[z], &ys = Y[z];\n            int nx = (int)xs.size(), ny = (int)ys.size();\n            if (nx >= ny) {\n                for (int j = 0; j < ny; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = ny; j < nx; j++) occ[idx3(D, xs[j], ys[0], z)] = 1;\n            } else {\n                for (int j = 0; j < nx; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = nx; j < ny; j++) occ[idx3(D, xs[0], ys[j], z)] = 1;\n            }\n        }\n    }\n    return occ;\n}\n\nstatic void fill_piece(int D, vector<int>& b, const Segment& seg, const Piece& pc, int id) {\n    int dx = 0, dy = 0, dz = 0;\n    if (seg.axis == 0) dx = 1;\n    else if (seg.axis == 1) dy = 1;\n    else dz = 1;\n\n    for (int t = 0; t < pc.len; t++) {\n        int x = seg.x + dx * (pc.off + t);\n        int y = seg.y + dy * (pc.off + t);\n        int z = seg.z + dz * (pc.off + t);\n        int ii = idx3(D, x, y, z);\n        // should be unassigned\n        // (in contest submissions we avoid asserts; keep safe check)\n        if (b[ii] != 0) {\n            // fallback: do nothing (should not happen)\n        }\n        b[ii] = id;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n    vector<string> f[2], r[2];\n    for (int i = 0; i < 2; i++) {\n        f[i].resize(D);\n        r[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> f[i][z];\n        for (int z = 0; z < D; z++) cin >> r[i][z];\n    }\n\n    const int S = 3; // number of construction types\n    vector<uint8_t> occ[2][S];\n    long long vol[2][S];\n\n    for (int i = 0; i < 2; i++) {\n        for (int s = 0; s < S; s++) {\n            occ[i][s] = build_occ(D, f[i], r[i], s);\n            vol[i][s] = volume_of(occ[i][s]);\n        }\n    }\n\n    // Precompute segments and length lists for each (obj, construction, axis).\n    vector<Segment> segs[2][S][3];\n    vector<int> lens[2][S][3];\n    for (int i = 0; i < 2; i++) for (int s = 0; s < S; s++) for (int a = 0; a < 3; a++) {\n        segs[i][s][a] = extract_segments(D, occ[i][s], a);\n        lens[i][s][a].reserve(segs[i][s][a].size());\n        for (auto &sg : segs[i][s][a]) lens[i][s][a].push_back(sg.len);\n    }\n\n    Plan best;\n    best.eval = 1e100L;\n\n    for (int s0 = 0; s0 < S; s0++) for (int s1 = 0; s1 < S; s1++) {\n        long long v0 = vol[0][s0];\n        long long v1 = vol[1][s1];\n        long double diff = (long double) llabs(v0 - v1);\n\n        for (int a0 = 0; a0 < 3; a0++) for (int a1 = 0; a1 < 3; a1++) {\n            long double pen = simulate_penalty(D, lens[0][s0][a0], lens[1][s1][a1]);\n            long double ev = diff + pen;\n            if (ev < best.eval) {\n                best = Plan{s0, s1, a0, a1, ev};\n            }\n        }\n    }\n\n    // Rebuild actual pieces using best choice\n    vector<Segment> A = segs[0][best.s0][best.a0];\n    vector<Segment> B = segs[1][best.s1][best.a1];\n\n    auto build_pieces = [&](vector<Segment>& SA, vector<Segment>& SB,\n                            vector<pair<Piece,Piece>>& shared,\n                            vector<Piece>& uniqueA, vector<Piece>& uniqueB) {\n        priority_queue<PQItem, vector<PQItem>, PQComp> pqA, pqB;\n        for (int i = 0; i < (int)SA.size(); i++) pqA.push({SA[i].len - SA[i].used, i});\n        for (int i = 0; i < (int)SB.size(); i++) pqB.push({SB[i].len - SB[i].used, i});\n\n        for (int L = D; L >= 1; L--) {\n            while (!pqA.empty() && !pqB.empty()) {\n                auto ta = pqA.top();\n                auto tb = pqB.top();\n                if (ta.rem < L || tb.rem < L) break;\n                pqA.pop(); pqB.pop();\n                int ida = ta.id, idb = tb.id;\n\n                Piece pa{ida, SA[ida].used, L};\n                Piece pb{idb, SB[idb].used, L};\n                SA[ida].used += L;\n                SB[idb].used += L;\n\n                shared.push_back({pa, pb});\n\n                int ra = SA[ida].len - SA[ida].used;\n                int rb = SB[idb].len - SB[idb].used;\n                if (ra > 0) pqA.push({ra, ida});\n                if (rb > 0) pqB.push({rb, idb});\n            }\n        }\n\n        for (int i = 0; i < (int)SA.size(); i++) {\n            int rem = SA[i].len - SA[i].used;\n            if (rem > 0) uniqueA.push_back(Piece{i, SA[i].used, rem});\n        }\n        for (int i = 0; i < (int)SB.size(); i++) {\n            int rem = SB[i].len - SB[i].used;\n            if (rem > 0) uniqueB.push_back(Piece{i, SB[i].used, rem});\n        }\n    };\n\n    vector<pair<Piece,Piece>> shared;\n    vector<Piece> unique0, unique1;\n    build_pieces(A, B, shared, unique0, unique1);\n\n    int n_shared = (int)shared.size();\n    int n0 = (int)unique0.size();\n    int n1 = (int)unique1.size();\n    int n = n_shared + n0 + n1;\n\n    vector<int> b0(D*D*D, 0), b1arr(D*D*D, 0);\n\n    int curId = 1;\n    for (int i = 0; i < n_shared; i++, curId++) {\n        fill_piece(D, b0, A[shared[i].first.segId], shared[i].first, curId);\n        fill_piece(D, b1arr, B[shared[i].second.segId], shared[i].second, curId);\n    }\n    for (int i = 0; i < n0; i++, curId++) {\n        fill_piece(D, b0, A[unique0[i].segId], unique0[i], curId);\n    }\n    for (int i = 0; i < n1; i++, curId++) {\n        fill_piece(D, b1arr, B[unique1[i].segId], unique1[i], curId);\n    }\n\n    cout << n << \"\\n\";\n    for (int i = 0; i < D*D*D; i++) {\n        if (i) cout << ' ';\n        cout << b0[i];\n    }\n    cout << \"\\n\";\n    for (int i = 0; i < D*D*D; i++) {\n        if (i) cout << ' ';\n        cout << b1arr[i];\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstatic inline int ceil_sqrt_ll(long long x) {\n    if (x <= 0) return 0;\n    long long r = (long long)floor(sqrt((long double)x));\n    while (r * r < x) ++r;\n    while ((r - 1) >= 0 && (r - 1) * (r - 1) >= x) --r;\n    return (int)r;\n}\n\nstruct Connector {\n    int N, M;\n    vector<Edge> edges;\n    vector<vector<tuple<int,long long,int>>> g; // to, w, edgeId\n\n    vector<vector<long long>> dist;  // N x N\n    vector<vector<int>> prevV;       // N x N\n    vector<vector<int>> prevE;       // N x N\n\n    vector<int> usedStamp; // size M\n    int stamp = 1;\n\n    Connector(int N_, int M_, const vector<Edge>& edges_)\n        : N(N_), M(M_), edges(edges_), g(N), dist(N, vector<long long>(N, (1LL<<62))),\n          prevV(N, vector<int>(N, -1)), prevE(N, vector<int>(N, -1)),\n          usedStamp(M, 0) {\n\n        for (int i = 0; i < M; i++) {\n            auto &e = edges[i];\n            g[e.u].push_back({e.v, e.w, i});\n            g[e.v].push_back({e.u, e.w, i});\n        }\n        all_pairs_dijkstra();\n    }\n\n    void all_pairs_dijkstra() {\n        for (int s = 0; s < N; s++) {\n            auto &ds = dist[s];\n            auto &pv = prevV[s];\n            auto &pe = prevE[s];\n            fill(ds.begin(), ds.end(), (1LL<<62));\n            fill(pv.begin(), pv.end(), -1);\n            fill(pe.begin(), pe.end(), -1);\n\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            ds[s] = 0;\n            pv[s] = s;\n            pe[s] = -1;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [dcur, v] = pq.top(); pq.pop();\n                if (dcur != ds[v]) continue;\n                for (auto [to, w, id] : g[v]) {\n                    long long nd = dcur + w;\n                    if (nd < ds[to]) {\n                        ds[to] = nd;\n                        pv[to] = v;\n                        pe[to] = id;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n        }\n    }\n\n    // Mark union edges of MST(terminals) in shortest-path metric into usedStamp==curStamp.\n    // Then ensure every terminal is reachable from 0; if not, add shortest path from 0.\n    // Return total edge weight of marked edges.\n    long long connection_cost_marked(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        if ((int)terminals.size() <= 1) return 0;\n\n        // Prim on terminals (complete graph by shortest path distances)\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) {\n                    key[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n\n        // Mark edges along chosen shortest paths\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break; // should not happen\n                usedStamp[eid] = curStamp;\n                cur = pvv;\n            }\n        }\n\n        // BFS reachability from 0 using currently marked edges\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true;\n        dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) {\n                    reach[to] = true;\n                    dq.push_back(to);\n                }\n            }\n        }\n\n        // Ensure all terminals reachable: if not, add shortest path from 0\n        for (int t : terminals) {\n            if (reach[t]) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                usedStamp[eid] = curStamp;\n                cur = pvv;\n            }\n        }\n\n        long long cost = 0;\n        for (int id = 0; id < M; id++) {\n            if (usedStamp[id] == curStamp) cost += edges[id].w;\n        }\n        // store curStamp as \"last\" stamp by decrementing stamp? easier: expose by returning it?\n        // We'll just copy out when needed via build_edges(terminals).\n        return cost;\n    }\n\n    vector<char> build_edges(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        if ((int)terminals.size() <= 1) return vector<char>(M, 0);\n\n        // Prim\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) {\n                    key[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n\n        // mark MST paths\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break;\n                usedStamp[eid] = curStamp;\n                cur = pvv;\n            }\n        }\n\n        // ensure reachability from 0\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true;\n        dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) {\n                    reach[to] = true;\n                    dq.push_back(to);\n                }\n            }\n        }\n        for (int t : terminals) {\n            if (reach[t]) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                usedStamp[eid] = curStamp;\n                cur = pvv;\n            }\n        }\n\n        vector<char> on(M, 0);\n        for (int id = 0; id < M; id++) if (usedStamp[id] == curStamp) on[id] = 1;\n        return on;\n    }\n\n    long long connection_cost(const vector<int>& terminals) {\n        // wrapper calling marked-cost; does not keep marks\n        return connection_cost_marked(terminals);\n    }\n};\n\nstruct State {\n    int N, K;\n    const vector<int> *x, *y;\n    const vector<int> *a, *b;\n    const vector<int> *dist2; // size K*N\n    const vector<array<int,100>> *order; // K x N sorted\n\n    vector<char> active;         // size N\n    vector<int> owner;           // size K\n    vector<vector<int>> resList; // N: resident indices\n    vector<int> maxD2;           // N\n    vector<int> P;               // N\n    vector<int> activeVerts;     // list of active stations (includes 0)\n    long long radioCost = 0;\n    long long edgeCost = 0;\n    long long totalCost = 0;\n\n    Connector *conn = nullptr;\n\n    inline int d2(int k, int i) const { return (*dist2)[k*N + i]; }\n\n    void recompute_from_active() {\n        resList.assign(N, {});\n        maxD2.assign(N, 0);\n        owner.assign(K, 0);\n\n        active[0] = 1; // root always active\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            for (int idx = 0; idx < N; idx++) {\n                int v = (*order)[k][idx];\n                if (active[v]) { chosen = v; break; }\n            }\n            if (chosen < 0) chosen = 0;\n            owner[k] = chosen;\n            resList[chosen].push_back(k);\n            maxD2[chosen] = max(maxD2[chosen], d2(k, chosen));\n        }\n\n        for (int i = 1; i < N; i++) if (resList[i].empty()) active[i] = 0;\n\n        activeVerts.clear();\n        for (int i = 0; i < N; i++) if (active[i]) activeVerts.push_back(i);\n\n        P.assign(N, 0);\n        radioCost = 0;\n        for (int i : activeVerts) {\n            int p = ceil_sqrt_ll(maxD2[i]);\n            // should never exceed 5000 if solution feasible\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = conn->connection_cost(activeVerts);\n        totalCost = radioCost + edgeCost;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n    vector<Edge> edges(M);\n    for (int j = 0; j < M; j++) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n    }\n\n    vector<int> a(K), b(K);\n    for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n    // Precompute resident->vertex squared distances and sorted orders\n    vector<int> dist2((size_t)K * N);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) {\n            long long dx = (long long)x[i] - a[k];\n            long long dy = (long long)y[i] - b[k];\n            long long d = dx*dx + dy*dy;\n            dist2[k*N + i] = (int)d;\n        }\n    }\n\n    vector<array<int,100>> order(K);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) order[k][i] = i;\n        auto cmp = [&](int i, int j) {\n            int di = dist2[k*N + i];\n            int dj = dist2[k*N + j];\n            if (di != dj) return di < dj;\n            return i < j;\n        };\n        sort(order[k].begin(), order[k].end(), cmp);\n    }\n\n    Connector conn(N, M, edges);\n\n    State st;\n    st.N = N; st.K = K;\n    st.x = &x; st.y = &y; st.a = &a; st.b = &b;\n    st.dist2 = &dist2;\n    st.order = &order;\n    st.conn = &conn;\n    st.active.assign(N, 1); // start with all stations enabled, then drop empty ones\n    st.recompute_from_active();\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_sec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n    const double TIME_LIMIT = 1.85;\n    const int D2_LIMIT = 5000 * 5000;\n\n    auto prune_greedy = [&]() {\n        while (elapsed_sec() < TIME_LIMIT) {\n            int bestV = -1;\n            long long bestNewRadio = st.radioCost;\n            long long bestNewEdge = st.edgeCost;\n            long long bestNewTotal = st.totalCost;\n            vector<pair<int,int>> bestMoves; // (resident, newOwner)\n            vector<int> bestTouched;\n\n            // Evaluate removing each active vertex (except root)\n            for (int v : st.activeVerts) {\n                if (v == 0) continue;\n                if (elapsed_sec() >= TIME_LIMIT) break;\n                if (st.resList[v].empty()) continue;\n\n                // Reassign residents of v to nearest active != v\n                vector<int> addedMaxD2(N, -1);\n                vector<int> touched;\n                vector<pair<int,int>> moves;\n                moves.reserve(st.resList[v].size());\n\n                bool ok = true;\n                for (int k : st.resList[v]) {\n                    int dest = -1;\n                    for (int idx = 0; idx < N; idx++) {\n                        int cand = order[k][idx];\n                        if (!st.active[cand]) continue;\n                        if (cand == v) continue;\n                        dest = cand;\n                        break;\n                    }\n                    if (dest < 0) { ok = false; break; }\n                    int d = dist2[k*N + dest];\n                    if (d > D2_LIMIT) { ok = false; break; } // cannot cover within 5000\n                    moves.push_back({k, dest});\n                    if (addedMaxD2[dest] < d) {\n                        if (addedMaxD2[dest] == -1) touched.push_back(dest);\n                        addedMaxD2[dest] = d;\n                    }\n                }\n                if (!ok) continue;\n\n                long long newRadio = st.radioCost - 1LL * st.P[v] * st.P[v];\n                for (int u : touched) {\n                    int oldMax = st.maxD2[u];\n                    int newMax = max(oldMax, addedMaxD2[u]);\n                    int oldP = st.P[u];\n                    int newP = ceil_sqrt_ll(newMax);\n                    if (newP > 5000) { ok = false; break; }\n                    newRadio += 1LL * newP * newP - 1LL * oldP * oldP;\n                }\n                if (!ok) continue;\n\n                // terminals after removal = activeVerts without v\n                vector<int> terminals;\n                terminals.reserve(st.activeVerts.size()-1);\n                for (int t : st.activeVerts) if (t != v) terminals.push_back(t);\n\n                long long newEdge = conn.connection_cost(terminals);\n                long long newTotal = newRadio + newEdge;\n\n                if (newTotal < bestNewTotal) {\n                    bestNewTotal = newTotal;\n                    bestNewRadio = newRadio;\n                    bestNewEdge = newEdge;\n                    bestV = v;\n                    bestMoves.swap(moves);\n                    bestTouched.swap(touched);\n                }\n            }\n\n            if (bestV == -1) break; // no improving removal\n\n            // Apply best removal\n            int v = bestV;\n\n            // Remove residents from v\n            // (We won't bother removing from vector efficiently; just rebuild resList[v] empty)\n            for (auto [k, dest] : bestMoves) {\n                st.owner[k] = dest;\n                st.resList[dest].push_back(k);\n                st.maxD2[dest] = max(st.maxD2[dest], dist2[k*N + dest]);\n            }\n\n            st.resList[v].clear();\n            st.maxD2[v] = 0;\n            st.P[v] = 0;\n            st.active[v] = 0;\n\n            // Update P for touched destinations (maxD2 only increased)\n            for (int u : bestTouched) {\n                st.P[u] = ceil_sqrt_ll(st.maxD2[u]);\n                if (st.P[u] > 5000) st.P[u] = 5000; // should not\n            }\n\n            // Update activeVerts list (remove v)\n            vector<int> newActiveVerts;\n            newActiveVerts.reserve(st.activeVerts.size()-1);\n            for (int t : st.activeVerts) if (t != v) newActiveVerts.push_back(t);\n            st.activeVerts.swap(newActiveVerts);\n\n            st.radioCost = bestNewRadio;\n            st.edgeCost = bestNewEdge;\n            st.totalCost = bestNewTotal;\n        }\n    };\n\n    prune_greedy();\n\n    // Try a few \"add one vertex\" improvements\n    for (int addIter = 0; addIter < 3 && elapsed_sec() < TIME_LIMIT; addIter++) {\n        int bestU = -1;\n        long long bestTotal = st.totalCost;\n\n        for (int u = 0; u < N && elapsed_sec() < TIME_LIMIT; u++) {\n            if (st.active[u]) continue;\n\n            // Compute new assignment under nearest-active with tie by index,\n            // but since only u is added and current owner is best among old actives,\n            // new owner is either old owner or u.\n            vector<int> cnt(N, 0);\n            vector<int> maxD2(N, 0);\n\n            for (int k = 0; k < K; k++) {\n                int cur = st.owner[k];\n                int du = dist2[k*N + u];\n                int dc = dist2[k*N + cur];\n                int nw = cur;\n                if (du < dc || (du == dc && u < cur)) nw = u;\n                cnt[nw]++;\n                maxD2[nw] = max(maxD2[nw], (nw == u ? du : dc)); // dc is dist to cur; ok because nw==cur then\n                if (nw != cur && nw != u) {\n                    // should never happen\n                }\n            }\n\n            if (cnt[u] == 0) continue; // adding u has no effect\n\n            long long radio = 0;\n            vector<int> terminals;\n            terminals.reserve(st.activeVerts.size() + 1);\n            terminals.push_back(0);\n            for (int t : st.activeVerts) if (t != 0) terminals.push_back(t);\n            if (u != 0) terminals.push_back(u);\n\n            // remove duplicates from terminals (0 may already be in activeVerts)\n            sort(terminals.begin(), terminals.end());\n            terminals.erase(unique(terminals.begin(), terminals.end()), terminals.end());\n\n            // But a vertex with cnt==0 shouldn't be a terminal (except 0). Remove them.\n            vector<int> filtered;\n            filtered.reserve(terminals.size());\n            for (int t : terminals) {\n                if (t == 0) filtered.push_back(t);\n                else if (cnt[t] > 0) filtered.push_back(t);\n            }\n\n            bool ok = true;\n            for (int t : filtered) {\n                int p = ceil_sqrt_ll(maxD2[t]);\n                if (p > 5000) { ok = false; break; }\n                radio += 1LL * p * p;\n            }\n            if (!ok) continue;\n\n            long long edge = conn.connection_cost(filtered);\n            long long total = radio + edge;\n\n            if (total < bestTotal) {\n                bestTotal = total;\n                bestU = u;\n            }\n        }\n\n        if (bestU == -1) break;\n\n        // Apply best addition: recompute from scratch to allow decreases in maxima\n        st.active[bestU] = 1;\n        st.recompute_from_active();\n        prune_greedy();\n    }\n\n    // Final edges for output\n    vector<int> terminals = st.activeVerts;\n    // ensure root included\n    if (find(terminals.begin(), terminals.end(), 0) == terminals.end()) terminals.push_back(0);\n    sort(terminals.begin(), terminals.end());\n    terminals.erase(unique(terminals.begin(), terminals.end()), terminals.end());\n\n    vector<char> on = conn.build_edges(terminals);\n\n    // Output P_1..P_N\n    for (int i = 0; i < N; i++) {\n        int pi = st.P[i];\n        if (pi < 0) pi = 0;\n        if (pi > 5000) pi = 5000;\n        cout << pi << (i+1==N?'\\n':' ');\n    }\n    // Output B_1..B_M\n    for (int j = 0; j < M; j++) {\n        cout << (int)on[j] << (j+1==M?'\\n':' ');\n    }\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int M = N * (N + 1) / 2;\nstatic constexpr int LIMIT = 10000;\n\nstruct PQEdge {\n    int diff;\n    int p, c; // parent, child (directed downward)\n    bool operator<(PQEdge const& other) const {\n        return diff < other.diff; // max-heap by diff\n    }\n};\n\nstruct Solver {\n    // value at node id\n    array<int, M> a{};\n    // position (node id) for each value 0..M-1\n    array<int, M> pos{};\n\n    // id -> (x,y)\n    array<int, M> X{}, Y{};\n    // parents/children by heap edges (not full 6-neighborhood)\n    array<array<int, 2>, M> par{};\n    array<int, M> parCnt{};\n    array<array<int, 2>, M> ch{};\n    array<int, M> chCnt{};\n\n    vector<array<int,4>> ops;\n\n    priority_queue<PQEdge> pq;\n\n    static int id(int x, int y) {\n        return x * (x + 1) / 2 + y;\n    }\n\n    void build_coords_and_graph() {\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v = id(x,y);\n                X[v] = x; Y[v] = y;\n\n                // parents\n                parCnt[v] = 0;\n                if (x > 0) {\n                    if (y > 0) par[v][parCnt[v]++] = id(x-1, y-1);\n                    if (y < x) par[v][parCnt[v]++] = id(x-1, y);\n                }\n\n                // children\n                chCnt[v] = 0;\n                if (x + 1 < N) {\n                    ch[v][chCnt[v]++] = id(x+1, y);\n                    ch[v][chCnt[v]++] = id(x+1, y+1);\n                }\n            }\n        }\n    }\n\n    inline void try_push_edge(int p, int c) {\n        if (a[p] > a[c]) pq.push(PQEdge{a[p] - a[c], p, c});\n    }\n\n    inline void add_incident_edges(int u) {\n        // u as parent\n        for (int i = 0; i < chCnt[u]; i++) {\n            int v = ch[u][i];\n            try_push_edge(u, v);\n        }\n        // u as child\n        for (int i = 0; i < parCnt[u]; i++) {\n            int p = par[u][i];\n            try_push_edge(p, u);\n        }\n    }\n\n    bool do_swap(int u, int v) {\n        if ((int)ops.size() >= LIMIT) return false;\n\n        ops.push_back({X[u], Y[u], X[v], Y[v]});\n\n        int au = a[u], av = a[v];\n        swap(a[u], a[v]);\n\n        pos[au] = v;\n        pos[av] = u;\n\n        add_incident_edges(u);\n        add_incident_edges(v);\n        return true;\n    }\n\n    void bubble_up(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestP = -1;\n            for (int i = 0; i < parCnt[u]; i++) {\n                int p = par[u][i];\n                if (a[p] > a[u]) {\n                    if (bestP == -1 || a[p] > a[bestP]) bestP = p;\n                }\n            }\n            if (bestP == -1) break;\n            if (!do_swap(bestP, u)) break;\n            u = bestP;\n        }\n    }\n\n    void bubble_down(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestC = -1;\n            for (int i = 0; i < chCnt[u]; i++) {\n                int c = ch[u][i];\n                if (a[u] > a[c]) {\n                    if (bestC == -1 || a[c] < a[bestC]) bestC = c;\n                }\n            }\n            if (bestC == -1) break;\n            if (!do_swap(u, bestC)) break;\n            u = bestC;\n        }\n    }\n\n    int count_violations() const {\n        int E = 0;\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = id(x,y);\n                int c1 = id(x+1,y);\n                int c2 = id(x+1,y+1);\n                if (a[p] > a[c1]) E++;\n                if (a[p] > a[c2]) E++;\n            }\n        }\n        return E;\n    }\n\n    void init_pq_all_violations() {\n        while (!pq.empty()) pq.pop();\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = id(x,y);\n                int c1 = id(x+1,y);\n                int c2 = id(x+1,y+1);\n                try_push_edge(p, c1);\n                try_push_edge(p, c2);\n            }\n        }\n    }\n\n    void solve() {\n        build_coords_and_graph();\n\n        // read input into a[]\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v;\n                cin >> v;\n                int node = id(x,y);\n                a[node] = v;\n                pos[v] = node;\n            }\n        }\n\n        init_pq_all_violations();\n\n        // Main loop: fix violations in order of largest (parent-child) difference.\n        // After a swap, locally bubble up/down to reduce future violations.\n        while (!pq.empty() && (int)ops.size() < LIMIT) {\n            auto e = pq.top(); pq.pop();\n            int p = e.p, c = e.c;\n            if (a[p] <= a[c]) continue; // stale\n            if (!do_swap(p, c)) break;\n\n            // After swap: smaller moved to p, larger moved to c.\n            bubble_up(p);\n            bubble_down(c);\n        }\n\n        // Safety: if somehow still violations and operations remain, restart PQ and continue.\n        // (Usually not needed, but cheap insurance.)\n        for (int rep = 0; rep < 2 && (int)ops.size() < LIMIT; rep++) {\n            if (count_violations() == 0) break;\n            init_pq_all_violations();\n            while (!pq.empty() && (int)ops.size() < LIMIT) {\n                auto e = pq.top(); pq.pop();\n                int p = e.p, c = e.c;\n                if (a[p] <= a[c]) continue;\n                if (!do_swap(p, c)) break;\n                bubble_up(p);\n                bubble_down(c);\n            }\n        }\n\n        // Output\n        cout << ops.size() << \"\\n\";\n        for (auto &op : ops) {\n            cout << op[0] << \" \" << op[1] << \" \" << op[2] << \" \" << op[3] << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    s.solve();\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct ArticulationResult {\n    vector<char> is_art;   // size V\n    vector<char> vis;      // reachable from root in current empty graph\n};\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    cin >> D >> N;\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    const int ei = 0, ej = (D - 1) / 2;\n    auto inside = [&](int i, int j) {\n        return 0 <= i && i < D && 0 <= j && j < D;\n    };\n    auto idx = [&](int i, int j) { return i * D + j; };\n    auto pos = [&](int v) { return pair<int,int>(v / D, v % D); };\n    const int root = idx(ei, ej);\n\n    const int M = D * D - 1 - N; // number of containers\n\n    // Precompute BFS distances on the static free-cell graph (ignoring containers).\n    const int V = D * D;\n    const int INF = 1e9;\n    vector<int> dist(V, INF);\n    {\n        queue<int> q;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                if (obstacle[ni][nj]) continue;\n                int u = idx(ni, nj);\n                if (dist[u] > dist[v] + 1) {\n                    dist[u] = dist[v] + 1;\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    // Build storable cells list and assign a global \"priority rank\".\n    vector<int> storable;\n    storable.reserve(M);\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == ei && j == ej) continue;\n        if (obstacle[i][j]) continue;\n        storable.push_back(idx(i, j));\n    }\n    sort(storable.begin(), storable.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        auto [ai, aj] = pos(a);\n        auto [bi, bj] = pos(b);\n        if (ai != bi) return ai < bi;\n        return aj < bj;\n    });\n\n    vector<int> rankv(V, -1);\n    for (int r = 0; r < (int)storable.size(); r++) rankv[storable[r]] = r;\n\n    vector<char> occupied(V, 0); // during placement: true if container already placed there\n    vector<int> label_at(V, -1); // final label at cell\n\n    auto is_empty_for_placement = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;     // entrance\n        return !occupied[v];\n    };\n\n    // Compute articulation points in current \"empty graph\" (for placement).\n    function<ArticulationResult()> compute_articulations = [&]() -> ArticulationResult {\n        vector<int> disc(V, -1), low(V, -1), parent(V, -1);\n        vector<char> is_art(V, 0), vis(V, 0);\n        int timer = 0;\n\n        function<void(int)> dfs = [&](int v) {\n            vis[v] = 1;\n            disc[v] = low[v] = timer++;\n            int child = 0;\n\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (!is_empty_for_placement(u)) continue;\n\n                if (disc[u] == -1) {\n                    parent[u] = v;\n                    child++;\n                    dfs(u);\n                    low[v] = min(low[v], low[u]);\n\n                    if (v != root && low[u] >= disc[v]) is_art[v] = 1;\n                } else if (u != parent[v]) {\n                    low[v] = min(low[v], disc[u]);\n                }\n            }\n\n            if (v == root && child > 1) is_art[v] = 1;\n        };\n\n        if (is_empty_for_placement(root)) dfs(root);\n\n        return {is_art, vis};\n    };\n\n    auto count_candidates_next = [&](int removed_cell) -> int {\n        occupied[removed_cell] = 1;\n        auto ar = compute_articulations();\n        int cnt = 0;\n        for (int v : storable) {\n            if (occupied[v]) continue;\n            if (!ar.vis[v]) continue;\n            if (!ar.is_art[v]) cnt++;\n        }\n        occupied[removed_cell] = 0;\n        return cnt;\n    };\n\n    // Placement phase (interactive).\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        auto ar = compute_articulations();\n\n        vector<int> cand;\n        cand.reserve(80);\n        for (int v : storable) {\n            if (occupied[v]) continue;\n            if (!ar.vis[v]) continue;        // should not happen if we keep connectivity\n            if (ar.is_art[v]) continue;      // removing would disconnect remaining empties\n            cand.push_back(v);\n        }\n\n        // Safety fallback: should never be empty, but just in case.\n        if (cand.empty()) {\n            // pick any reachable empty cell\n            for (int v : storable) if (!occupied[v] && ar.vis[v]) { cand.push_back(v); break; }\n        }\n\n        int best = cand[0];\n        long long bestScore = (1LL<<62);\n\n        for (int v : cand) {\n            int rc = rankv[v];\n            int assignCost = abs(rc - t);             // match label to cell priority\n            int flex = (step + 1 < M) ? count_candidates_next(v) : 0;\n\n            // Weighted score (assignment dominates; flex is tie-breaker-ish).\n            long long score = 100LL * assignCost - 1LL * flex;\n\n            // Small tie breaker: prefer farther cells if equal (often keeps core robust).\n            score = score * 100 + dist[v];\n\n            if (score < bestScore) {\n                bestScore = score;\n                best = v;\n            }\n        }\n\n        occupied[best] = 1;\n        label_at[best] = t;\n        auto [pi, pj] = pos(best);\n        cout << pi << ' ' << pj << '\\n' << flush;\n    }\n\n    // Removal phase (offline, after all placements).\n    vector<char> removed(V, 0); // false => still has container (except obstacles/entrance)\n    auto is_empty_for_removal_bfs = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;\n        // storable cells are occupied until removed\n        return removed[v];\n    };\n\n    for (int step = 0; step < M; step++) {\n        // BFS reachable empty cells\n        vector<char> vis(V, 0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_for_removal_bfs(u)) continue;\n                vis[u] = 1;\n                q.push(u);\n            }\n        }\n\n        // Find removable container with smallest label: occupied cell adjacent to reachable empty.\n        int bestCell = -1;\n        int bestLabel = INT_MAX;\n\n        for (int v : storable) {\n            if (removed[v]) continue; // already shipped\n            // reachable if adjacent to some visited empty cell\n            auto [i, j] = pos(v);\n            bool ok = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (vis[u]) { ok = true; break; }\n            }\n            if (!ok) continue;\n\n            int lab = label_at[v];\n            if (lab < bestLabel) {\n                bestLabel = lab;\n                bestCell = v;\n            }\n        }\n\n        // Should always exist.\n        if (bestCell == -1) {\n            // Fallback: pick any remaining container adjacent to entrance area (shouldn't happen)\n            for (int v : storable) if (!removed[v]) { bestCell = v; break; }\n        }\n\n        removed[bestCell] = 1;\n        auto [qi, qj] = pos(bestCell);\n        cout << qi << ' ' << qj << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int DX[4] = {1, -1, 0, 0};\nstatic constexpr int DY[4] = {0, 0, 1, -1};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> orig(n, vector<int>(n));\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) cin >> orig[i][j];\n    }\n\n    const int C = m + 1; // colors 0..m\n\n    auto is_boundary = [&](int i, int j) -> bool {\n        return (i == 0 || i == n - 1 || j == 0 || j == n - 1);\n    };\n\n    // Compute required adjacency from the original map\n    vector<vector<int>> req(C, vector<int>(C, 0));\n    vector<int> req0(C, 0); // req0[c] == req[0][c]\n\n    // adjacency between non-zero colors\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = orig[i][j];\n            if (i + 1 < n) {\n                int b = orig[i + 1][j];\n                if (a != b) {\n                    req[a][b] = req[b][a] = 1;\n                }\n            }\n            if (j + 1 < n) {\n                int b = orig[i][j + 1];\n                if (a != b) {\n                    req[a][b] = req[b][a] = 1;\n                }\n            }\n        }\n    }\n    // adjacency with outside 0: boundary sides\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (!is_boundary(i, j)) continue;\n            int c = orig[i][j];\n            req0[c] = 1;\n            req[0][c] = req[c][0] = 1;\n        }\n    }\n\n    vector<int> allow0(C, 0);\n    for (int c = 1; c <= m; c++) allow0[c] = req0[c];\n\n    // Current grid (start from original)\n    vector<vector<int>> g = orig;\n\n    // size of each color\n    vector<int> sz(C, 0);\n    for (int i = 0; i < n; i++)\n        for (int j = 0; j < n; j++)\n            sz[g[i][j]]++;\n\n    // Current adjacency counts (number of edges between colors)\n    // cnt[u][v] for u<v, u,v>=1 ; and cnt0[c] for edges between 0 and c.\n    vector<vector<int>> cnt(C, vector<int>(C, 0));\n    vector<int> cnt0(C, 0);\n\n    auto add_edge = [&](int u, int v, int delta) {\n        if (u == v) return;\n        if (u == 0) {\n            cnt0[v] += delta;\n            return;\n        }\n        if (v == 0) {\n            cnt0[u] += delta;\n            return;\n        }\n        if (u > v) swap(u, v);\n        cnt[u][v] += delta;\n    };\n\n    // initialize counts from g (initially equals orig)\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = g[i][j];\n            if (i + 1 < n) add_edge(a, g[i + 1][j], +1);\n            if (j + 1 < n) add_edge(a, g[i][j + 1], +1);\n            // outside edges\n            if (i == 0) add_edge(0, a, +1);\n            if (i == n - 1) add_edge(0, a, +1);\n            if (j == 0) add_edge(0, a, +1);\n            if (j == n - 1) add_edge(0, a, +1);\n        }\n    }\n\n    // Random engine\n    uint64_t seed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937 rng((uint32_t)seed);\n\n    // visited stamps for BFS connectivity checks\n    vector<int> vis(n * n, 0);\n    int vis_stamp = 1;\n\n    auto idx = [&](int i, int j) { return i * n + j; };\n\n    auto is_candidate = [&](int i, int j) -> bool {\n        if (g[i][j] == 0) return false;\n        if (is_boundary(i, j)) return true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (0 <= ni && ni < n && 0 <= nj && nj < n) {\n                if (g[ni][nj] == 0) return true;\n            }\n        }\n        return false;\n    };\n\n    auto connected_after_remove = [&](int i, int j, int c) -> bool {\n        // find a start cell (a neighbor of same color)\n        int si = -1, sj = -1;\n        int same_deg = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (0 <= ni && ni < n && 0 <= nj && nj < n && g[ni][nj] == c) {\n                same_deg++;\n                if (si == -1) { si = ni; sj = nj; }\n            }\n        }\n        // size[c] > 1 guaranteed by caller, so should have at least one neighbor in a connected region,\n        // but be defensive:\n        if (si == -1) return false;\n\n        // Leaf removal is always safe for connectivity.\n        if (same_deg <= 1) return true;\n\n        int target = sz[c] - 1;\n        vis_stamp++;\n        deque<pair<int,int>> q;\n        q.push_back({si, sj});\n        vis[idx(si, sj)] = vis_stamp;\n        int cntv = 1;\n\n        while (!q.empty()) {\n            auto [x, y] = q.front();\n            q.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < n && 0 <= ny && ny < n)) continue;\n                if (nx == i && ny == j) continue;\n                if (g[nx][ny] != c) continue;\n                int id = idx(nx, ny);\n                if (vis[id] == vis_stamp) continue;\n                vis[id] = vis_stamp;\n                q.push_back({nx, ny});\n                cntv++;\n            }\n        }\n        return cntv == target;\n    };\n\n    auto can_delete = [&](int i, int j) -> bool {\n        int c = g[i][j];\n        if (c == 0) return false;\n        if (!allow0[c]) return false;     // would create (0,c) adjacency\n        if (sz[c] <= 1) return false;     // can't remove last cell\n\n        if (!is_candidate(i, j)) return false; // would create enclosed 0 hole\n\n        // Collect neighbor info\n        int numSame = 0;\n        int numZero = 0;\n        int rem[101]; // m=100 fixed in this contest, but keep generic within 0..100\n        memset(rem, 0, sizeof(rem));\n        int neigh_colors[4];\n        int neigh_cnt = 0;\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d;\n            if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) d = 0;\n            else d = g[ni][nj];\n\n            if (d == c) {\n                numSame++;\n            } else if (d == 0) {\n                numZero++;\n            } else {\n                if (!allow0[d]) return false; // would create new forbidden adjacency (0,d)\n                if (rem[d] == 0) neigh_colors[neigh_cnt++] = d;\n                rem[d]++;\n            }\n        }\n\n        // Ensure (0,c) stays adjacent if required\n        // newCnt0c = cnt0[c] + numSame (new 0-c edges) - numZero (removed 0-c edges)\n        int newCnt0c = cnt0[c] + numSame - numZero;\n        if (req0[c] && newCnt0c <= 0) return false;\n\n        // Ensure all required (c,d) adjacencies stay\n        for (int t = 0; t < neigh_cnt; t++) {\n            int d = neigh_colors[t];\n            int u = c, v = d;\n            if (u > v) swap(u, v);\n            if (req[u][v]) {\n                if (cnt[u][v] - rem[d] <= 0) return false;\n            }\n        }\n\n        // Connectivity of c after removal\n        if (!connected_after_remove(i, j, c)) return false;\n\n        return true;\n    };\n\n    auto apply_delete = [&](int i, int j) {\n        int c = g[i][j];\n        // Update adjacency counts via 4 sides\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d;\n            if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) d = 0;\n            else d = g[ni][nj];\n\n            if (d == c) {\n                // c-c (no edge) becomes 0-c\n                add_edge(0, c, +1);\n            } else if (d == 0) {\n                // 0-c edge disappears\n                add_edge(0, c, -1);\n            } else {\n                // c-d disappears, 0-d appears\n                add_edge(c, d, -1);\n                add_edge(0, d, +1);\n            }\n        }\n        g[i][j] = 0;\n        sz[c]--;\n    };\n\n    // Candidate pool: start from boundary cells\n    vector<int> cand;\n    cand.reserve(n * n * 4);\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (is_boundary(i, j)) cand.push_back(idx(i, j));\n        }\n    }\n\n    Timer timer;\n    const double TIME_LIMIT = 1.90; // keep margin\n\n    // Random deletion loop\n    while (!cand.empty() && timer.elapsed_sec() < TIME_LIMIT) {\n        int r = (int)(rng() % cand.size());\n        int id = cand[r];\n        cand[r] = cand.back();\n        cand.pop_back();\n\n        int i = id / n;\n        int j = id % n;\n        if (g[i][j] == 0) continue;\n        if (!is_candidate(i, j)) continue;\n\n        if (can_delete(i, j)) {\n            apply_delete(i, j);\n            // neighbors become candidates\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (0 <= ni && ni < n && 0 <= nj && nj < n) {\n                    if (g[ni][nj] != 0) cand.push_back(idx(ni, nj));\n                }\n            }\n        }\n    }\n\n    // Final verification (to avoid WA). If fails, output original.\n    auto verify = [&]() -> bool {\n        // Check all colors 1..m exist and connected\n        vector<int> seen(C, 0);\n        for (int i = 0; i < n; i++)\n            for (int j = 0; j < n; j++)\n                seen[g[i][j]]++;\n\n        for (int c = 1; c <= m; c++) if (seen[c] == 0) return false;\n\n        // connectivity check for each non-zero color\n        vector<int> vis2(n*n, 0);\n        int stamp2 = 1;\n        for (int c = 1; c <= m; c++) {\n            // find a start\n            int si = -1, sj = -1;\n            for (int i = 0; i < n && si == -1; i++) {\n                for (int j = 0; j < n; j++) {\n                    if (g[i][j] == c) { si = i; sj = j; break; }\n                }\n            }\n            if (si == -1) return false;\n            stamp2++;\n            deque<pair<int,int>> q;\n            q.push_back({si, sj});\n            vis2[idx(si, sj)] = stamp2;\n            int cntv = 1;\n            while (!q.empty()) {\n                auto [x,y] = q.front(); q.pop_front();\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + DX[k], ny = y + DY[k];\n                    if (!(0 <= nx && nx < n && 0 <= ny && ny < n)) continue;\n                    if (g[nx][ny] != c) continue;\n                    int id2 = idx(nx, ny);\n                    if (vis2[id2] == stamp2) continue;\n                    vis2[id2] = stamp2;\n                    q.push_back({nx, ny});\n                    cntv++;\n                }\n            }\n            if (cntv != seen[c]) return false;\n        }\n\n        // Check 0 is outside-connected: BFS on padded grid of zeros\n        int N = n + 2;\n        auto at = [&](int x, int y) -> int {\n            // padded coords: 0..N-1\n            if (x == 0 || y == 0 || x == N-1 || y == N-1) return 0;\n            return g[x-1][y-1];\n        };\n        vector<char> vz(N*N, 0);\n        deque<pair<int,int>> q0;\n        q0.push_back({0,0});\n        vz[0] = 1;\n        while (!q0.empty()) {\n            auto [x,y] = q0.front(); q0.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < N && 0 <= ny && ny < N)) continue;\n                int nid = nx * N + ny;\n                if (vz[nid]) continue;\n                if (at(nx, ny) != 0) continue;\n                vz[nid] = 1;\n                q0.push_back({nx, ny});\n            }\n        }\n        for (int x = 1; x <= n; x++) {\n            for (int y = 1; y <= n; y++) {\n                if (g[x-1][y-1] == 0) {\n                    int pid = x * N + y;\n                    if (!vz[pid]) return false; // enclosed hole\n                }\n            }\n        }\n\n        // Check adjacency graph equals req\n        vector<vector<int>> outAdj(C, vector<int>(C, 0));\n        auto markAdj = [&](int u, int v) {\n            if (u == v) return;\n            outAdj[u][v] = outAdj[v][u] = 1;\n        };\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int a = g[i][j];\n                if (i + 1 < n) markAdj(a, g[i+1][j]);\n                if (j + 1 < n) markAdj(a, g[i][j+1]);\n                if (i == 0) markAdj(0, a);\n                if (i == n - 1) markAdj(0, a);\n                if (j == 0) markAdj(0, a);\n                if (j == n - 1) markAdj(0, a);\n            }\n        }\n        for (int u = 0; u <= m; u++) {\n            for (int v = u+1; v <= m; v++) {\n                if (outAdj[u][v] != req[u][v]) return false;\n            }\n        }\n        return true;\n    };\n\n    if (!verify()) {\n        g = orig; // fallback safe\n    }\n\n    // Output\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (j) cout << ' ';\n            cout << g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    using ull = unsigned long long;\n    ull x;\n    explicit XorShift(ull seed = 88172645463325252ULL) : x(seed) {}\n    ull nextUll() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextUll() % (ull)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<vector<int>> bins;\n    vector<int> ans;\n\n    // cache for singleton comparisons: cmp(i,j) in {-1,0,1} meaning wi ? wj\n    // store only for i<j\n    vector<vector<int8_t>> itemCmp; // 2D NxN, 2: unknown, else -1/0/1\n\n    XorShift rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    char querySets(const vector<int>& L, const vector<int>& R) {\n        // Must not exceed Q in communication.\n        // Caller must ensure used < Q and L,R non-empty disjoint.\n        cout << (int)L.size() << \" \" << (int)R.size();\n        for (int x : L) cout << \" \" << x;\n        for (int x : R) cout << \" \" << x;\n        cout << \"\\n\";\n        cout.flush();\n\n        string s;\n        cin >> s;\n        used++;\n        return s[0];\n    }\n\n    int cmpItemNoCache(int i, int j) {\n        // return -1 if wi<wj, 0 if =, +1 if wi>wj\n        vector<int> L = {i}, R = {j};\n        char r = querySets(L, R);\n        if (r == '<') return -1;\n        if (r == '>') return +1;\n        return 0;\n    }\n\n    int cmpItem(int i, int j) {\n        if (i == j) return 0;\n        int a = min(i, j), b = max(i, j);\n        int8_t &v = itemCmp[a][b];\n        if (v != 2) {\n            int res = (int)v;\n            if (i == a) return res;\n            return -res;\n        }\n        int res = cmpItemNoCache(i, j);\n        // store as (a ? b)\n        int store = (i == a ? res : -res);\n        itemCmp[a][b] = (int8_t)store;\n        return res;\n    }\n\n    // Compare two bin sums: return -1 if binA < binB, 0 if =, +1 if >\n    int cmpBins(int a, int b) {\n        char r = querySets(bins[a], bins[b]);\n        if (r == '<') return -1;\n        if (r == '>') return +1;\n        return 0;\n    }\n\n    int findLightestBin() {\n        int best = 0;\n        for (int i = 1; i < D; i++) {\n            if (used >= Q) break;\n            int c = cmpBins(best, i);\n            if (c == +1) best = i; // best heavier -> i is lighter\n        }\n        return best;\n    }\n\n    int findHeaviestBin() {\n        int best = 0;\n        for (int i = 1; i < D; i++) {\n            if (used >= Q) break;\n            int c = cmpBins(best, i);\n            if (c == -1) best = i; // best lighter -> i is heavier\n        }\n        return best;\n    }\n\n    vector<int> pickKDistinctBins(int k) {\n        vector<int> pool(D);\n        iota(pool.begin(), pool.end(), 0);\n        for (int i = 0; i < k; i++) {\n            int j = rng.nextInt(i, D - 1);\n            swap(pool[i], pool[j]);\n        }\n        pool.resize(k);\n        return pool;\n    }\n\n    int tournamentLightest(const vector<int>& cand) {\n        int best = cand[0];\n        for (int idx = 1; idx < (int)cand.size(); idx++) {\n            if (used >= Q) break;\n            int b = cand[idx];\n            int c = cmpBins(best, b);\n            if (c == +1) best = b;\n        }\n        return best;\n    }\n\n    void moveItemBetweenBins(int item, int from, int to) {\n        // remove from \"from\"\n        auto &vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); i++) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        ans[item] = to;\n    }\n\n    vector<int> buildOrderByPivots(int P, const vector<int>& items) {\n        // Choose first P as pivots (items already shuffled).\n        vector<int> piv(items.begin(), items.begin() + P);\n\n        // Insertion sort pivots ascending by weight\n        for (int i = 1; i < P; i++) {\n            int x = piv[i];\n            int j = i - 1;\n            while (j >= 0) {\n                if (used >= Q) break;\n                int c = cmpItem(piv[j], x); // piv[j] ? x\n                if (c <= 0) break; // piv[j] <= x\n                piv[j + 1] = piv[j];\n                j--;\n            }\n            piv[j + 1] = x;\n        }\n\n        vector<vector<int>> bucket(P + 1);\n        vector<char> isPivot(N, 0);\n        for (int x : piv) isPivot[x] = 1;\n\n        // Classify others by upper_bound among pivots (ascending):\n        // bucket idx in [0..P], where 0: <piv0, P: >= piv[P-1]\n        for (int x : items) {\n            if (isPivot[x]) continue;\n            int lo = 0, hi = P;\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                if (used >= Q) break;\n                int c = cmpItem(x, piv[mid]); // x ? piv[mid]\n                if (c < 0) hi = mid;\n                else lo = mid + 1;\n            }\n            bucket[lo].push_back(x);\n        }\n\n        // Build heavy -> light order:\n        vector<int> order;\n        order.reserve(N);\n\n        // bucket[P] (>= heaviest pivot), then piv[P-1], then bucket[P-1], ...\n        for (int j = P; j >= 1; j--) {\n            auto &b = bucket[j];\n            // shuffle within bucket for diversity\n            for (int t = (int)b.size() - 1; t > 0; t--) {\n                int u = rng.nextInt(0, t);\n                swap(b[t], b[u]);\n            }\n            for (int x : b) order.push_back(x);\n            order.push_back(piv[j - 1]);\n        }\n        // finally lightest bucket[0]\n        {\n            auto &b = bucket[0];\n            for (int t = (int)b.size() - 1; t > 0; t--) {\n                int u = rng.nextInt(0, t);\n                swap(b[t], b[u]);\n            }\n            for (int x : b) order.push_back(x);\n        }\n\n        // In rare case used>=Q breaks binary searches early; still must be a permutation.\n        // Ensure all items included once.\n        vector<char> seen(N, 0);\n        vector<int> fixed;\n        fixed.reserve(N);\n        for (int x : order) {\n            if (!seen[x]) {\n                seen[x] = 1;\n                fixed.push_back(x);\n            }\n        }\n        for (int x : items) if (!seen[x]) fixed.push_back(x);\n        return fixed;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        ans.assign(N, 0);\n        bins.assign(D, {});\n        itemCmp.assign(N, vector<int8_t>(N, 2));\n\n        // deterministic seed based on input (contest-friendly)\n        unsigned long long seed = 1234567ULL;\n        seed ^= (unsigned long long)N * 1000003ULL;\n        seed ^= (unsigned long long)D * 10007ULL;\n        seed ^= (unsigned long long)Q * 97ULL;\n        rng = XorShift(seed);\n\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        // shuffle items\n        for (int i = N - 1; i > 0; i--) {\n            int j = rng.nextInt(0, i);\n            swap(items[i], items[j]);\n        }\n\n        // Decide pivot count P (2/4/8) under a simple budget constraint.\n        auto costForP = [&](int P) -> int {\n            if (P <= 1) return 0;\n            int pivSort = P * (P - 1) / 2;\n            int lg = 0;\n            while ((1 << lg) < P) lg++;\n            // upper_bound uses lg comparisons worst-case\n            int classify = (N - P) * lg;\n            return pivSort + classify;\n        };\n\n        int minAssign = max(0, N - D); // keep at least 1 comparison per item possible (k=2) if desired\n        int P = 2;\n        for (int cand : {8, 4, 2}) {\n            if (cand <= N && costForP(cand) <= max(0, Q - minAssign)) {\n                P = cand;\n                break;\n            }\n        }\n\n        vector<int> order = buildOrderByPivots(P, items);\n\n        // --- Initial seeding: 1 item per bin (no queries) ---\n        for (int b = 0; b < D; b++) {\n            int it = order[b];\n            bins[b].push_back(it);\n            ans[it] = b;\n        }\n\n        // --- Greedy assignment with adaptive k-choice ---\n        for (int t = D; t < N; t++) {\n            int it = order[t];\n\n            int remainingItems = N - t;\n            int remainingQueries = Q - used;\n            if (remainingItems <= 0) break;\n\n            // keep ~30% of remaining queries for improvement phase\n            long long budgetAssign = (long long)remainingQueries * 7 / 10;\n            int compsPerItem = 0;\n            if (remainingItems > 0) compsPerItem = (int)(budgetAssign / remainingItems);\n\n            // k candidates => (k-1) comparisons\n            int k = min(D, compsPerItem + 1);\n            k = max(k, 2);\n            if (remainingQueries <= 0) {\n                // no queries left, random placement\n                int b = rng.nextInt(0, D - 1);\n                bins[b].push_back(it);\n                ans[it] = b;\n                continue;\n            }\n            if (k - 1 > remainingQueries) k = remainingQueries + 1;\n            if (k < 2) k = 2;\n\n            vector<int> cand = pickKDistinctBins(k);\n            int best = tournamentLightest(cand);\n\n            bins[best].push_back(it);\n            ans[it] = best;\n\n            if (used >= Q) break;\n        }\n\n        // --- Local improvement: move from heaviest to lightest ---\n        while (used < Q) {\n            // Need at least (D-1)+(D-1)+1 queries to do something meaningful\n            if (Q - used < 2 * (D - 1) + 1) break;\n\n            int L = findLightestBin();\n            if (used >= Q) break;\n            int H = findHeaviestBin();\n            if (used >= Q) break;\n\n            if (L == H) break;\n            // If already equal, stop\n            {\n                int c = cmpBins(H, L);\n                if (used >= Q) break;\n                if (c == 0) break;\n                // if somehow H is not heavier due to ties/noise, skip\n                if (c < 0) continue;\n            }\n\n            if ((int)bins[H].size() <= 1) break; // keep bins non-empty for further queries\n\n            // Try moving one item x from H to L.\n            // Evaluate each candidate by comparing (H\\{x}) vs (L U {x}).\n            int bestEq = -1;\n            int bestOvershoot = -1;  // makes newH < newL (overshoot)\n            int bestStillHeavy = -1; // keeps newH > newL\n\n            auto lighterItem = [&](int a, int b) -> int {\n                // return the lighter one (by singleton cmp)\n                if (a == -1) return b;\n                if (b == -1) return a;\n                if (used >= Q) return a;\n                int c = cmpItem(a, b); // a ? b\n                if (c <= 0) return a;\n                return b;\n            };\n            auto heavierItem = [&](int a, int b) -> int {\n                // return the heavier one\n                if (a == -1) return b;\n                if (b == -1) return a;\n                if (used >= Q) return a;\n                int c = cmpItem(a, b);\n                if (c >= 0) return a;\n                return b;\n            };\n\n            // Pre-copy L set once\n            vector<int> setL = bins[L];\n\n            // We'll test all candidates except leaving at least one in H.\n            for (int idx = 0; idx < (int)bins[H].size(); idx++) {\n                if (used >= Q) break;\n                if ((int)bins[H].size() <= 1) break;\n\n                int x = bins[H][idx];\n\n                // Build setA = H without x\n                vector<int> setA;\n                setA.reserve(bins[H].size() - 1);\n                for (int y : bins[H]) if (y != x) setA.push_back(y);\n                if (setA.empty()) continue; // keep non-empty for query\n\n                // Build setB = L with x\n                vector<int> setB = setL;\n                setB.push_back(x);\n\n                char r = querySets(setA, setB); // compares newH vs newL\n                if (r == '=') {\n                    bestEq = x;\n                    break;\n                } else if (r == '<') {\n                    // overshoot: newH < newL, want smallest x among overshoots\n                    bestOvershoot = lighterItem(bestOvershoot, x);\n                } else { // '>'\n                    // still heavy: want largest x to reduce more\n                    bestStillHeavy = heavierItem(bestStillHeavy, x);\n                }\n\n                // if queries running low, stop early\n                if (Q - used < 2) break;\n            }\n\n            int chosen = -1;\n            if (bestEq != -1) chosen = bestEq;\n            else if (bestOvershoot != -1) chosen = bestOvershoot;\n            else chosen = bestStillHeavy;\n\n            if (chosen == -1) break;\n\n            // Apply move (ensure H keeps >=1 item)\n            if ((int)bins[H].size() <= 1) break;\n            moveItemBetweenBins(chosen, H, L);\n        }\n\n        // --- Dummy queries to reach exactly Q ---\n        // Compare {0} vs {1} repeatedly (valid because disjoint and non-empty).\n        while (used < Q) {\n            vector<int> L = {0}, R = {1};\n            (void)querySets(L, R);\n        }\n\n        // --- Output final assignment ---\n        for (int i = 0; i < N; i++) {\n            if (i) cout << \" \";\n            cout << ans[i];\n        }\n        cout << \"\\n\";\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Weights {\n    double wHeight = 0.08;\n    double wMinUrg = 220.0;\n    double wTopUrg = 90.0;\n    double wMinAtTopExtra = 260.0;\n\n    double badTopBase = 5000.0;\n    double badTopSlope = 8.0;\n\n    double bonusMinGT = 60.0;\n    double bonusTopGT = 25.0;\n\n    int candK = 3;        // number of candidates for lookahead\n    int lookahead = 8;    // number of removals to simulate in lookahead\n};\n\nstruct Result {\n    long long energy = (1LL<<60);\n    vector<pair<int,int>> ops;\n};\n\nstatic constexpr int N = 200;\nstatic constexpr int M = 10;\n\nstruct StackInfo {\n    int h = 0;\n    int top = INT_MAX;\n    int mn = INT_MAX;\n    int posMinFromTop = 0; // 0 means min is on top\n    bool empty = true;\n};\n\nstatic inline uint64_t xorshift64(uint64_t &x) {\n    x ^= x << 7;\n    x ^= x >> 9;\n    return x;\n}\n\nstruct Solver {\n    vector<vector<int>> st0;\n\n    Solver(const vector<vector<int>>& init) : st0(init) {}\n\n    static pair<int,int> locate(const vector<vector<int>>& st, int v) {\n        for (int i = 0; i < (int)st.size(); i++) {\n            for (int j = 0; j < (int)st[i].size(); j++) {\n                if (st[i][j] == v) return {i, j};\n            }\n        }\n        return {-1, -1};\n    }\n\n    static vector<StackInfo> buildInfo(const vector<vector<int>>& st) {\n        vector<StackInfo> info(st.size());\n        for (int i = 0; i < (int)st.size(); i++) {\n            StackInfo si;\n            si.h = (int)st[i].size();\n            si.empty = (si.h == 0);\n            if (!si.empty) {\n                si.top = st[i].back();\n                int mn = INT_MAX, idx = -1;\n                for (int j = 0; j < si.h; j++) {\n                    if (st[i][j] < mn) {\n                        mn = st[i][j];\n                        idx = j;\n                    }\n                }\n                si.mn = mn;\n                si.posMinFromTop = (si.h - 1) - idx;\n            }\n            info[i] = si;\n        }\n        return info;\n    }\n\n    static void applyMove(vector<vector<int>>& st, int s, int start, int d) {\n        // move suffix st[s][start..end) to top of st[d]\n        vector<int> pile;\n        pile.reserve(st[s].size() - start);\n        for (int i = start; i < (int)st[s].size(); i++) pile.push_back(st[s][i]);\n        st[s].resize(start);\n        for (int x : pile) st[d].push_back(x);\n    }\n\n    static void applyPop(vector<vector<int>>& st, int s) {\n        st[s].pop_back();\n    }\n\n    static double destPenalty(\n        int t,\n        int s, int d,\n        int k,\n        int pileMax,\n        const vector<StackInfo>& info,\n        const Weights& w,\n        double noise = 0.0\n    ) {\n        if (d == s) return 1e100;\n        if (info[d].empty) return -1e50; // extremely preferred\n\n        int h = info[d].h;\n        int top = info[d].top;\n        int mn = info[d].mn;\n        int posMin = info[d].posMinFromTop;\n\n        // t is global minimum remaining, so top,mn > t for destination stacks typically\n        double deltaMin = double(mn - t);\n        double deltaTop = double(top - t);\n\n        double p = 0.0;\n        p += w.wHeight * double(h + k);\n        p += w.wMinUrg * double(k) / (deltaMin + 1.0);\n        p += w.wTopUrg * double(k) / (deltaTop + 1.0);\n\n        // If the minimum is currently on top, burying it can create a \"new required move\"\n        if (posMin == 0) {\n            p += w.wMinAtTopExtra * double(k + 1) / (deltaMin + 1.0);\n        }\n\n        // Avoid placing a pile on top of a smaller top (tends to bury earlier-needed items)\n        if (top < pileMax) {\n            p += w.badTopBase + w.badTopSlope * double(pileMax - top);\n        }\n\n        // Slight bonuses if destination is \"safely larger\"\n        if (mn > pileMax) p -= w.bonusMinGT;\n        if (top > pileMax) p -= w.bonusTopGT;\n\n        p += noise;\n        return p;\n    }\n\n    // Base greedy destination selection without lookahead (deterministic)\n    static int chooseDestBaseNoLookahead(\n        const vector<vector<int>>& st,\n        int t,\n        int s, int startAbove, int k, int pileMax,\n        const Weights& w\n    ) {\n        auto info = buildInfo(st);\n\n        // If there is an empty stack, use it (best buffer)\n        for (int d = 0; d < (int)st.size(); d++) {\n            if (d == s) continue;\n            if (info[d].empty) return d;\n        }\n\n        double bestP = 1e100;\n        int bestD = -1;\n        for (int d = 0; d < (int)st.size(); d++) {\n            if (d == s) continue;\n            double p = destPenalty(t, s, d, k, pileMax, info, w, 0.0);\n            if (p < bestP) {\n                bestP = p;\n                bestD = d;\n            }\n        }\n        if (bestD < 0) bestD = (s + 1) % (int)st.size();\n        return bestD;\n    }\n\n    static long long simulateEnergy(\n        vector<vector<int>> st,\n        int tStart,\n        int maxRemovals,\n        const Weights& w\n    ) {\n        long long e = 0;\n        int t = tStart;\n        int removed = 0;\n        while (t <= N && removed < maxRemovals) {\n            auto [s, pos] = locate(st, t);\n            if (s < 0) break;\n\n            if ((int)st[s].size() - 1 == pos) {\n                // pop t\n                applyPop(st, s);\n                t++;\n                removed++;\n            } else {\n                int start = pos + 1;\n                int k = (int)st[s].size() - start;\n                int pileMax = 0;\n                for (int i = start; i < (int)st[s].size(); i++) pileMax = max(pileMax, st[s][i]);\n\n                int d = chooseDestBaseNoLookahead(st, t, s, start, k, pileMax, w);\n                applyMove(st, s, start, d);\n                e += (long long)k + 1;\n            }\n        }\n        return e;\n    }\n\n    static int chooseDestWithLookahead(\n        const vector<vector<int>>& st,\n        int t,\n        int s, int startAbove, int k, int pileMax,\n        const Weights& w,\n        uint64_t &rng\n    ) {\n        auto info = buildInfo(st);\n\n        // Empty stack: take immediately\n        for (int d = 0; d < (int)st.size(); d++) {\n            if (d == s) continue;\n            if (info[d].empty) return d;\n        }\n\n        // Compute penalties, take best candK\n        vector<pair<double,int>> cand;\n        cand.reserve(st.size());\n        for (int d = 0; d < (int)st.size(); d++) {\n            if (d == s) continue;\n            // tiny noise to diversify trials\n            double noise = (double)(int)(xorshift64(rng) % 1000) * 1e-9;\n            double p = destPenalty(t, s, d, k, pileMax, info, w, noise);\n            cand.push_back({p, d});\n        }\n        sort(cand.begin(), cand.end());\n        int K = min<int>(w.candK, (int)cand.size());\n\n        // Lookahead among top candidates\n        long long bestScore = (1LL<<62);\n        int bestD = cand[0].second;\n\n        for (int i = 0; i < K; i++) {\n            int d = cand[i].second;\n            vector<vector<int>> st2 = st;\n            applyMove(st2, s, startAbove, d);\n            long long score = (long long)k + 1;\n            score += simulateEnergy(st2, t, w.lookahead, w);\n            if (score < bestScore) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\n    Result run(const Weights& w, uint64_t seed) {\n        uint64_t rng = seed;\n        vector<vector<int>> st = st0;\n        vector<pair<int,int>> ops;\n        ops.reserve(1000);\n\n        long long energy = 0;\n        int t = 1;\n        while (t <= N) {\n            auto [s, pos] = locate(st, t);\n            if (s < 0) break;\n\n            if ((int)st[s].size() - 1 == pos) {\n                // operation 2\n                ops.push_back({t, 0});\n                applyPop(st, s);\n                t++;\n            } else {\n                // move boxes above t in one shot: choose v = box directly above t\n                int start = pos + 1;\n                int k = (int)st[s].size() - start;\n                int v = st[s][start];\n\n                int pileMax = 0;\n                for (int i = start; i < (int)st[s].size(); i++) pileMax = max(pileMax, st[s][i]);\n\n                int d = chooseDestWithLookahead(st, t, s, start, k, pileMax, w, rng);\n\n                // operation 1\n                ops.push_back({v, d + 1});\n                applyMove(st, s, start, d);\n                energy += (long long)k + 1;\n            }\n\n            if ((int)ops.size() > 5000) {\n                // should never happen for this strategy; still keep safe\n                break;\n            }\n        }\n\n        Result res;\n        res.energy = energy;\n        res.ops = std::move(ops);\n        return res;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> init(m);\n    for (int i = 0; i < m; i++) {\n        init[i].resize(n / m);\n        for (int j = 0; j < n / m; j++) cin >> init[i][j];\n    }\n\n    Solver solver(init);\n\n    auto start = chrono::high_resolution_clock::now();\n\n    // Base weights\n    Weights base;\n\n    Result best;\n    best.energy = (1LL<<60);\n\n    // Multiple trials within time\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    int trials = 0;\n    while (true) {\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - start).count();\n        if (elapsed > 1.90) break;\n\n        Weights w = base;\n\n        // Randomly perturb weights (except trial 0)\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)trials;\n        uint64_t rng = seed;\n\n        auto rand01 = [&]() -> double {\n            return (double)(xorshift64(rng) % 1000000) / 1000000.0;\n        };\n        auto mult = [&](double x, double lo, double hi) {\n            return x * (lo + (hi - lo) * rand01());\n        };\n\n        if (trials > 0) {\n            w.wHeight = mult(w.wHeight, 0.6, 1.4);\n            w.wMinUrg = mult(w.wMinUrg, 0.7, 1.3);\n            w.wTopUrg = mult(w.wTopUrg, 0.7, 1.3);\n            w.wMinAtTopExtra = mult(w.wMinAtTopExtra, 0.7, 1.4);\n\n            w.badTopBase = mult(w.badTopBase, 0.6, 1.4);\n            w.badTopSlope = mult(w.badTopSlope, 0.6, 1.6);\n\n            w.bonusMinGT = mult(w.bonusMinGT, 0.5, 1.6);\n            w.bonusTopGT = mult(w.bonusTopGT, 0.5, 1.6);\n\n            // sometimes vary lookahead\n            if (rand01() < 0.3) w.lookahead = 6;\n            if (rand01() < 0.3) w.lookahead = 10;\n            w.candK = 3;\n        }\n\n        Result cur = solver.run(w, seed);\n        if (cur.energy < best.energy && (int)cur.ops.size() <= 5000) {\n            best = std::move(cur);\n        }\n\n        trials++;\n    }\n\n    // Output best operation sequence\n    for (auto [v, i] : best.ops) {\n        cout << v << \" \" << i << \"\\n\";\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline char oppositeDir(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    return 'L';\n}\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\nstatic const char DIRCH[4] = {'U','D','L','R'};\n\nstruct AnalysisResult {\n    long double metric = 1e100L;       // sumSq / L  (sumSq = sum d * sum interval^2)\n    long long sumSq = (1LL<<62);\n    vector<int> pos;                  // pos[k] = vertex before move k (k=0..L), pos[0]=start, pos[L]=start\n    vector<int> bestGap;              // per vertex\n    vector<int> bestInsertPos;        // per vertex: move index where we insert detour\n    bool ok = false;\n};\n\nstruct Solver {\n    int N;\n    int V;\n    vector<string> h, v;\n    vector<int> d;                    // size V\n    vector<array<int,4>> nxt;         // -1 if wall\n\n    // For BFS path reconstruction\n    vector<int> bfsDist, bfsPrev;\n    vector<char> bfsPrevMove;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    int id(int i, int j) const { return i*N + j; }\n\n    void readInput() {\n        cin >> N;\n        V = N*N;\n        h.resize(N-1);\n        v.resize(N);\n        for (int i=0;i<N-1;i++) cin >> h[i];\n        for (int i=0;i<N;i++) cin >> v[i];\n        d.assign(V, 0);\n        for (int i=0;i<N;i++) for (int j=0;j<N;j++) {\n            int x; cin >> x;\n            d[id(i,j)] = x;\n        }\n        nxt.assign(V, array<int,4>{-1,-1,-1,-1});\n        for (int i=0;i<N;i++) for (int j=0;j<N;j++) {\n            int u = id(i,j);\n            // U\n            if (i > 0 && h[i-1][j] == '0') nxt[u][0] = id(i-1,j);\n            // D\n            if (i < N-1 && h[i][j] == '0') nxt[u][1] = id(i+1,j);\n            // L\n            if (j > 0 && v[i][j-1] == '0') nxt[u][2] = id(i,j-1);\n            // R\n            if (j < N-1 && v[i][j] == '0') nxt[u][3] = id(i,j+1);\n        }\n\n        bfsDist.assign(V, -1);\n        bfsPrev.assign(V, -1);\n        bfsPrevMove.assign(V, 0);\n    }\n\n    // Build a spanning tree using a greedy priority (high d, shallow depth).\n    // Returns parent and parentDir (dir from parent -> node).\n    void buildSpanningTree(vector<int>& parent, vector<char>& parentDir, vector<int>& order) {\n        parent.assign(V, -1);\n        parentDir.assign(V, '?');\n        vector<int> depth(V, 0);\n        vector<char> vis(V, 0);\n        order.clear();\n        order.reserve(V);\n\n        const int ROOT = 0;\n        vis[ROOT] = 1;\n        order.push_back(ROOT);\n\n        // candidate: (key, parent, node, dir)\n        // maximize key\n        struct Cand { int key; int p; int x; char dir; };\n        struct Cmp { bool operator()(const Cand& a, const Cand& b) const { return a.key < b.key; } };\n        priority_queue<Cand, vector<Cand>, Cmp> pq;\n\n        auto pushNeighbors = [&](int u){\n            for (int k=0;k<4;k++) {\n                int w = nxt[u][k];\n                if (w < 0 || vis[w]) continue;\n                // depth penalty\n                // gamma tuned lightly; larger => shallower tree.\n                static const int gamma = 15;\n                int candDepth = depth[u] + 1;\n                int key = d[w] - gamma * candDepth;\n                pq.push(Cand{key, u, w, DIRCH[k]});\n            }\n        };\n\n        pushNeighbors(ROOT);\n\n        while ((int)order.size() < V) {\n            if (pq.empty()) break; // should not happen (graph connected)\n            auto c = pq.top(); pq.pop();\n            if (vis[c.x]) continue;\n            vis[c.x] = 1;\n            parent[c.x] = c.p;\n            parentDir[c.x] = c.dir;\n            depth[c.x] = depth[c.p] + 1;\n            order.push_back(c.x);\n            pushNeighbors(c.x);\n        }\n        // Graph guaranteed connected; still, ensure all visited\n        // If something went wrong, fall back to simple BFS tree.\n        if ((int)order.size() < V) {\n            parent.assign(V, -1);\n            parentDir.assign(V, '?');\n            order.clear();\n            order.reserve(V);\n\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1;\n            q.push_back(0);\n            order.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent[w]=u;\n                    parentDir[w]=DIRCH[k];\n                    q.push_back(w);\n                    order.push_back(w);\n                }\n            }\n        }\n    }\n\n    // Generate Euler tour of tree (each edge twice).\n    string buildEulerRoute(const vector<int>& parent, const vector<char>& parentDir, const vector<int>& order) {\n        vector<vector<int>> children(V);\n        children.assign(V, {});\n        for (int x=1;x<V;x++) {\n            int p = parent[x];\n            if (p >= 0) children[p].push_back(x);\n        }\n\n        // subtree sums for child ordering\n        vector<long long> sub(V);\n        for (int i=0;i<V;i++) sub[i] = d[i];\n        for (int idx=(int)order.size()-1; idx>=1; --idx) {\n            int x = order[idx];\n            int p = parent[x];\n            if (p >= 0) sub[p] += sub[x];\n        }\n        for (int u=0;u<V;u++) {\n            auto &ch = children[u];\n            sort(ch.begin(), ch.end(), [&](int a, int b){\n                if (sub[a] != sub[b]) return sub[a] > sub[b];\n                return d[a] > d[b];\n            });\n        }\n\n        string route;\n        route.reserve(2*(V-1)+10);\n\n        function<void(int)> dfs = [&](int u){\n            for (int x: children[u]) {\n                route.push_back(parentDir[x]);\n                dfs(x);\n                route.push_back(oppositeDir(parentDir[x]));\n            }\n        };\n        dfs(0);\n        return route;\n    }\n\n    // Analyze route: positions, sumSq, best gaps and suggested insertion move-index.\n    AnalysisResult analyzeRoute(const string& route) {\n        AnalysisResult res;\n        int L = (int)route.size();\n        if (L <= 0) return res;\n\n        res.pos.assign(L+1, 0);\n        vector<int> first(V, -1), last(V, -1);\n        res.bestGap.assign(V, -1);\n        res.bestInsertPos.assign(V, 0);\n\n        long long sumSq = 0;\n        int cur = 0;\n        res.pos[0] = 0;\n\n        // scan moves, time t = move index i (0..L-1), arrival node = pos[i+1]\n        for (int i=0;i<L;i++) {\n            int k = dirId(route[i]);\n            int nx = nxt[cur][k];\n            if (nx < 0) return res; // illegal\n            cur = nx;\n            res.pos[i+1] = cur;\n\n            int t = i;\n            int vtx = cur;\n            if (first[vtx] == -1) {\n                first[vtx] = last[vtx] = t;\n            } else {\n                int prevT = last[vtx];\n                int gap = t - prevT;\n                sumSq += 1LL * d[vtx] * gap * gap;\n\n                if (gap > res.bestGap[vtx]) {\n                    res.bestGap[vtx] = gap;\n                    int midT = prevT + gap/2;\n                    int insertPos = (midT + 1) % L; // move index\n                    res.bestInsertPos[vtx] = insertPos;\n                }\n                last[vtx] = t;\n            }\n        }\n        // Must return to start to be a valid cycle\n        if (cur != 0) return res;\n\n        // wrap intervals\n        for (int vtx=0; vtx<V; vtx++) {\n            if (first[vtx] == -1) return res; // unvisited => invalid\n            int gap = (first[vtx] + L) - last[vtx];\n            sumSq += 1LL * d[vtx] * gap * gap;\n\n            if (gap > res.bestGap[vtx]) {\n                res.bestGap[vtx] = gap;\n                long long midT = (long long)last[vtx] + gap/2;\n                int midMod = (int)(midT % L);\n                int insertPos = (midMod + 1) % L;\n                res.bestInsertPos[vtx] = insertPos;\n            }\n        }\n\n        res.sumSq = sumSq;\n        res.metric = (long double)sumSq / (long double)L;\n        res.ok = true;\n        return res;\n    }\n\n    // Compute metric only (sumSq/L). Assumes route is legal.\n    long double computeMetric(const string& route, vector<int>& first, vector<int>& last) {\n        int L = (int)route.size();\n        if (L <= 0) return 1e100L;\n        fill(first.begin(), first.end(), -1);\n        fill(last.begin(), last.end(), -1);\n\n        long long sumSq = 0;\n        int cur = 0;\n        for (int i=0;i<L;i++) {\n            int k = dirId(route[i]);\n            int nx = nxt[cur][k];\n            if (nx < 0) return 1e100L;\n            cur = nx;\n            int t = i;\n            int vtx = cur;\n            if (first[vtx] == -1) {\n                first[vtx] = last[vtx] = t;\n            } else {\n                int gap = t - last[vtx];\n                sumSq += 1LL * d[vtx] * gap * gap;\n                last[vtx] = t;\n            }\n        }\n        if (cur != 0) return 1e100L;\n        for (int vtx=0; vtx<V; vtx++) {\n            if (first[vtx] == -1) return 1e100L;\n            int gap = (first[vtx] + L) - last[vtx];\n            sumSq += 1LL * d[vtx] * gap * gap;\n        }\n        return (long double)sumSq / (long double)L;\n    }\n\n    // BFS shortest path from s to t, return move string.\n    string shortestPathMoves(int s, int t) {\n        if (s == t) return {};\n        fill(bfsDist.begin(), bfsDist.end(), -1);\n        deque<int> q;\n        bfsDist[s] = 0;\n        bfsPrev[s] = -1;\n        q.push_back(s);\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop_front();\n            int du = bfsDist[u];\n            for (int k=0;k<4;k++) {\n                int w = nxt[u][k];\n                if (w < 0) continue;\n                if (bfsDist[w] != -1) continue;\n                bfsDist[w] = du + 1;\n                bfsPrev[w] = u;\n                bfsPrevMove[w] = DIRCH[k];\n                if (w == t) break;\n                q.push_back(w);\n            }\n            if (bfsDist[t] != -1) break;\n        }\n        if (bfsDist[t] == -1) return {}; // should not happen\n\n        string path;\n        int cur = t;\n        while (cur != s) {\n            char mv = bfsPrevMove[cur];\n            path.push_back(mv);\n            cur = bfsPrev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    void improveByDetours(string& route, double timeLimitSec = 1.85) {\n        auto start = chrono::steady_clock::now();\n        vector<int> tmpFirst(V, -1), tmpLast(V, -1);\n\n        for (int iter=0; iter<2000; iter++) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed > timeLimitSec) break;\n\n            AnalysisResult curA = analyzeRoute(route);\n            if (!curA.ok) break;\n            long double curMetric = curA.metric;\n            int L = (int)route.size();\n            if (L >= 100000) break;\n\n            struct Cand {\n                int vtx;\n                long long benefit;\n                int insertPos;\n                int startPosVtx;\n                long double ratio;\n                string go;\n            };\n\n            // pick top-K by d * bestGap^2\n            vector<pair<long long,int>> keys;\n            keys.reserve(V);\n            for (int vtx=0; vtx<V; vtx++) {\n                int g = curA.bestGap[vtx];\n                if (g <= 1) continue;\n                long long benefit = 1LL * d[vtx] * g * g;\n                keys.push_back({benefit, vtx});\n            }\n            if (keys.empty()) break;\n            nth_element(keys.begin(), keys.begin() + min<int>(30, (int)keys.size()), keys.end(),\n                        [&](auto& a, auto& b){ return a.first > b.first; });\n            int K = min<int>(30, (int)keys.size());\n            keys.resize(K);\n            sort(keys.begin(), keys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n            vector<Cand> cands;\n            cands.reserve(K);\n            for (auto [benefit, vtx] : keys) {\n                int insertPos = curA.bestInsertPos[vtx]; // 0..L-1\n                int startPosVtx = curA.pos[insertPos];   // vertex before move insertPos\n                string go = shortestPathMoves(startPosVtx, vtx);\n                if (go.empty()) continue;\n                int dist = (int)go.size();\n                int addLen = 2*dist;\n                if (L + addLen > 100000) continue;\n                long double ratio = (long double)benefit / (long double)(addLen);\n                cands.push_back(Cand{vtx, benefit, insertPos, startPosVtx, ratio, std::move(go)});\n            }\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                return a.ratio > b.ratio;\n            });\n            int M = min<int>(5, (int)cands.size());\n\n            // Try a few best candidates with actual metric evaluation; take best improvement.\n            long double bestMetric = curMetric;\n            int bestIdx = -1;\n            string bestDetour;\n\n            for (int i=0; i<M; i++) {\n                double el2 = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n                if (el2 > timeLimitSec) break;\n\n                const auto& c = cands[i];\n                string det = c.go;\n                // backtrack along same path\n                for (int k=(int)c.go.size()-1; k>=0; k--) det.push_back(oppositeDir(c.go[k]));\n\n                route.insert((size_t)c.insertPos, det);\n                long double met = computeMetric(route, tmpFirst, tmpLast);\n                route.erase((size_t)c.insertPos, det.size());\n\n                if (met + 1e-18L < bestMetric) {\n                    bestMetric = met;\n                    bestIdx = i;\n                    bestDetour = std::move(det);\n                }\n            }\n\n            if (bestIdx == -1) break; // no improving insertion found\n\n            // Apply the best improving insertion\n            route.insert((size_t)cands[bestIdx].insertPos, bestDetour);\n        }\n    }\n\n    void solve() {\n        vector<int> parent, order;\n        vector<char> parentDir;\n        buildSpanningTree(parent, parentDir, order);\n        string route = buildEulerRoute(parent, parentDir, order);\n\n        // Improve\n        improveByDetours(route);\n\n        // Safety: length limit\n        if ((int)route.size() > 100000) route.resize(100000);\n\n        cout << route << \"\\n\";\n    }\n};\n\nint main() {\n    Solver s;\n    s.readInput();\n    s.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    short r, c;\n};\n\nstatic inline int manhattan(const Pos& a, const Pos& b) {\n    return abs((int)a.r - (int)b.r) + abs((int)a.c - (int)b.c);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<string> t(M);\n    for (int k = 0; k < M; k++) cin >> t[k];\n\n    // Positions of each letter\n    array<vector<Pos>, 26> pos;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            pos[A[i][j] - 'A'].push_back(Pos{(short)i, (short)j});\n        }\n    }\n\n    Pos start{(short)si, (short)sj};\n\n    // Precompute D[c][d] = min Manhattan distance between any occurrence of c and d.\n    const int INF = 1e9;\n    array<array<int, 26>, 26> D;\n    for (int c = 0; c < 26; c++) {\n        for (int d = 0; d < 26; d++) {\n            int best = INF;\n            for (const auto &p : pos[c]) {\n                for (const auto &q : pos[d]) {\n                    best = min(best, manhattan(p, q));\n                }\n            }\n            D[c][d] = best;\n        }\n    }\n\n    // Distance from start to a letter\n    array<int, 26> Dstart;\n    for (int c = 0; c < 26; c++) {\n        int best = INF;\n        for (const auto &p : pos[c]) best = min(best, manhattan(start, p));\n        Dstart[c] = best;\n    }\n\n    auto overlap_len_suffix_prefix = [&](const string& suffix4, const string& w) -> int {\n        int sl = (int)suffix4.size();\n        int maxl = min(4, sl);\n        for (int l = maxl; l >= 1; --l) {\n            bool ok = true;\n            for (int i = 0; i < l; i++) {\n                if (suffix4[sl - l + i] != w[i]) { ok = false; break; }\n            }\n            if (ok) return l;\n        }\n        return 0;\n    };\n\n    auto update_suffix4 = [&](string& suffix4, const string& appended) {\n        for (char ch : appended) {\n            if ((int)suffix4.size() < 4) suffix4.push_back(ch);\n            else {\n                suffix4.erase(suffix4.begin());\n                suffix4.push_back(ch);\n            }\n        }\n    };\n\n    auto build_from_order_with_overlap = [&](const vector<int>& order) -> string {\n        string S = t[order[0]];\n        string suffix4;\n        for (int i = max(0, (int)S.size() - 4); i < (int)S.size(); i++) suffix4.push_back(S[i]);\n        for (int k = 1; k < (int)order.size(); k++) {\n            const string& w = t[order[k]];\n            int l = overlap_len_suffix_prefix(suffix4, w);\n            string add = w.substr(l);\n            S += add;\n            update_suffix4(suffix4, add);\n        }\n        return S;\n    };\n\n    auto approx_add_cost = [&](char curLast, const string& w, int l) -> int {\n        // Approx additional cost to append w with overlap length l.\n        // Uses D[][] + 1 per typed char.\n        int cost = 0;\n        if (l == 0) {\n            cost += D[curLast - 'A'][w[0] - 'A'] + 1;\n            for (int i = 1; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        } else {\n            for (int i = l; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        }\n        return cost;\n    };\n\n    auto approx_start_cost = [&](const string& w) -> int {\n        int cost = Dstart[w[0] - 'A'] + 1;\n        for (int i = 1; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        return cost;\n    };\n\n    // Exact DP for a fixed string S: returns (cost, coordinates per character).\n    auto solve_dp = [&](const string& S) -> pair<long long, vector<Pos>> {\n        const long long LINF = (1LL<<60);\n        int L = (int)S.size();\n        vector<vector<short>> parent(L);\n        vector<long long> dpPrev, dpCur;\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            int mcur = (int)pos[c].size();\n            dpCur.assign(mcur, LINF);\n            parent[k].assign(mcur, (short)-1);\n\n            if (k == 0) {\n                for (int i = 0; i < mcur; i++) {\n                    dpCur[i] = (long long)manhattan(start, pos[c][i]) + 1;\n                }\n            } else {\n                int pc = S[k-1] - 'A';\n                int mprev = (int)pos[pc].size();\n                for (int i = 0; i < mcur; i++) {\n                    long long best = LINF;\n                    short bestj = -1;\n                    for (int j = 0; j < mprev; j++) {\n                        long long cand = dpPrev[j] + (long long)manhattan(pos[pc][j], pos[c][i]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestj = (short)j;\n                        }\n                    }\n                    dpCur[i] = best;\n                    parent[k][i] = bestj;\n                }\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        // Choose best ending\n        int lastC = S.back() - 'A';\n        int mend = (int)pos[lastC].size();\n        long long bestCost = (1LL<<60);\n        int bestIdx = 0;\n        for (int i = 0; i < mend; i++) {\n            if (dpPrev[i] < bestCost) {\n                bestCost = dpPrev[i];\n                bestIdx = i;\n            }\n        }\n\n        vector<Pos> path(L);\n        int idx = bestIdx;\n        for (int k = L-1; k >= 0; k--) {\n            int c = S[k] - 'A';\n            path[k] = pos[c][idx];\n            idx = parent[k][idx];\n        }\n        return {bestCost, path};\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)seed);\n\n    vector<string> candidates;\n\n    // Candidate 0: given order with overlaps\n    {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Candidate 1: nearest-neighbor order by last->first letter distance\n    {\n        int bestStart = 0;\n        int bestVal = INF;\n        for (int i = 0; i < M; i++) {\n            int v = approx_start_cost(t[i]);\n            if (v < bestVal) { bestVal = v; bestStart = i; }\n        }\n        vector<int> order;\n        order.reserve(M);\n        vector<char> used(M, 0);\n        order.push_back(bestStart);\n        used[bestStart] = 1;\n\n        for (int it = 1; it < M; it++) {\n            int cur = order.back();\n            char lastCh = t[cur][4];\n            int bestj = -1;\n            int bestd = INF;\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int d = D[lastCh - 'A'][t[j][0] - 'A'];\n                if (d < bestd) { bestd = d; bestj = j; }\n            }\n            used[bestj] = 1;\n            order.push_back(bestj);\n        }\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Candidate 2+: movement-aware greedy with random restarts\n    auto greedy_construct = [&](int tries, double noise0) {\n        vector<int> all(M);\n        iota(all.begin(), all.end(), 0);\n\n        // Precompute start cost ranking to pick better starts\n        vector<pair<int,int>> startRank;\n        startRank.reserve(M);\n        for (int i = 0; i < M; i++) startRank.push_back({approx_start_cost(t[i]), i});\n        sort(startRank.begin(), startRank.end());\n\n        uniform_real_distribution<double> uni01(0.0, 1.0);\n\n        for (int tr = 0; tr < tries; tr++) {\n            vector<int> rem = all;\n\n            // pick start among top-K\n            int K = 10;\n            int pick = startRank[min((int)startRank.size()-1, (int)(uni01(rng) * K))].second;\n\n            // remove pick from rem\n            {\n                int idx = -1;\n                for (int i = 0; i < (int)rem.size(); i++) if (rem[i] == pick) { idx = i; break; }\n                rem[idx] = rem.back();\n                rem.pop_back();\n            }\n\n            string S = t[pick];\n            char curLast = S.back();\n\n            string suffix4;\n            for (int i = max(0, (int)S.size() - 4); i < (int)S.size(); i++) suffix4.push_back(S[i]);\n\n            int stepsDone = 1;\n            while (!rem.empty()) {\n                double temp = noise0 * (1.0 - (double)stepsDone / (double)M);\n                int bestIdxInRem = 0;\n                double bestScore = 1e100;\n                int R = (int)rem.size();\n\n                for (int ri = 0; ri < R; ri++) {\n                    int widx = rem[ri];\n                    const string& w = t[widx];\n                    int l = overlap_len_suffix_prefix(suffix4, w);\n                    int base = approx_add_cost(curLast, w, l);\n\n                    double score = (double)base + temp * uni01(rng);\n                    if (score < bestScore) {\n                        bestScore = score;\n                        bestIdxInRem = ri;\n                    }\n                }\n\n                int widx = rem[bestIdxInRem];\n                const string& w = t[widx];\n                int l = overlap_len_suffix_prefix(suffix4, w);\n                string add = w.substr(l);\n                S += add;\n                update_suffix4(suffix4, add);\n                curLast = S.back();\n\n                rem[bestIdxInRem] = rem.back();\n                rem.pop_back();\n                stepsDone++;\n            }\n            candidates.push_back(S);\n        }\n    };\n\n    greedy_construct(12, 1.0);\n\n    // Random shuffle candidates\n    for (int k = 0; k < 3; k++) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Evaluate candidates with exact DP and pick the best\n    long long bestCost = (1LL<<60);\n    vector<Pos> bestPath;\n    string bestS;\n\n    for (const string& S : candidates) {\n        if ((int)S.size() > 5000) continue; // must be within operation limit\n        auto [cost, path] = solve_dp(S);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestPath = std::move(path);\n            bestS = S;\n        }\n    }\n\n    // Output coordinates (one per operation)\n    for (auto &p : bestPath) {\n        cout << (int)p.r << ' ' << (int)p.c << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<uint64_t> bits;   // bitmask over N^2 cells\n    vector<int> cells;       // list of indices for output\n    int k;                   // number of cells\n    double obs;              // estimated true sum v(S)\n    double w;                // weight in objective\n    bool exact;              // drill => exact\n};\n\nstruct Placement {\n    int di, dj;\n    vector<uint64_t> bits;\n    vector<int> cells;           // indices\n    vector<int16_t> inter;       // intersection counts for each query (appended)\n    vector<int> neigh;           // neighbor placement indices (shifts)\n};\n\nstruct Field {\n    vector<Placement> ps;\n};\n\nstruct Solution {\n    vector<int> idx; // chosen placement per field\n    double cost;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    // deterministic hash mixing\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Solver {\n    int N, M;\n    double eps;\n    int N2;\n    int L; // number of uint64 blocks\n    int op_limit;\n    int ops = 0;\n\n    vector<Field> fields;\n    vector<Query> queries;\n\n    vector<int> drilledVal; // -1 unknown else exact v\n    int drilledCnt = 0;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, double eps_) : N(N_), M(M_), eps(eps_) {\n        N2 = N * N;\n        L = (N2 + 63) / 64;\n        op_limit = 2 * N2;\n        drilledVal.assign(N2, -1);\n        rng.seed((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    }\n\n    // --- interactive I/O ---\n    int drillCell(int i, int j) {\n        cout << \"q 1 \" << i << \" \" << j << endl;\n        ops++;\n        int v;\n        if (!(cin >> v)) exit(0);\n        return v;\n    }\n\n    int divineCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"q \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int y;\n        if (!(cin >> y)) exit(0);\n        return y;\n    }\n\n    int answerCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"a \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int ok;\n        if (!(cin >> ok)) exit(0);\n        return ok;\n    }\n\n    // reserve enough operations to drill all remaining cells + final answer\n    bool canSpendOps(int extra) const {\n        int remainingToDrill = N2 - drilledCnt;\n        // need remainingToDrill drills + 1 final answer after spending extra\n        return ops + extra + remainingToDrill + 1 <= op_limit;\n    }\n\n    // --- bit helpers ---\n    inline bool bitGet(const vector<uint64_t>& b, int idx) const {\n        return (b[idx >> 6] >> (idx & 63)) & 1ULL;\n    }\n    inline void bitSet(vector<uint64_t>& b, int idx) const {\n        b[idx >> 6] |= 1ULL << (idx & 63);\n    }\n    int popcountAnd(const vector<uint64_t>& a, const vector<uint64_t>& b) const {\n        int s = 0;\n        for (int t = 0; t < L; t++) s += __builtin_popcountll(a[t] & b[t]);\n        return s;\n    }\n\n    // --- build placements for each field ---\n    void buildPlacements(const vector<vector<pair<int,int>>>& shapes) {\n        fields.resize(M);\n        for (int f = 0; f < M; f++) {\n            const auto& shp = shapes[f];\n            int maxI = 0, maxJ = 0;\n            for (auto [x,y]: shp) {\n                maxI = max(maxI, x);\n                maxJ = max(maxJ, y);\n            }\n            int diMax = N - maxI - 1;\n            int djMax = N - maxJ - 1;\n            // map translation -> placement index\n            vector<vector<int>> mp(diMax+1, vector<int>(djMax+1, -1));\n\n            for (int di = 0; di <= diMax; di++) {\n                for (int dj = 0; dj <= djMax; dj++) {\n                    Placement p;\n                    p.di = di; p.dj = dj;\n                    p.bits.assign(L, 0ULL);\n                    p.cells.reserve(shp.size());\n                    for (auto [x,y]: shp) {\n                        int i = di + x;\n                        int j = dj + y;\n                        int idx = i*N + j;\n                        p.cells.push_back(idx);\n                        bitSet(p.bits, idx);\n                    }\n                    fields[f].ps.push_back(std::move(p));\n                    mp[di][dj] = (int)fields[f].ps.size()-1;\n                }\n            }\n            // neighbors by +/-1 shifts\n            for (auto &p: fields[f].ps) {\n                int di = p.di, dj = p.dj;\n                static int dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n                for (auto &d: dd) {\n                    int ndi = di + d[0], ndj = dj + d[1];\n                    if (0 <= ndi && ndi <= diMax && 0 <= ndj && ndj <= djMax) {\n                        int ni = mp[ndi][ndj];\n                        if (ni >= 0) p.neigh.push_back(ni);\n                    }\n                }\n            }\n        }\n    }\n\n    // --- add query + update all placement intersection arrays ---\n    void addQuery(const vector<int>& cellIdx, const vector<uint64_t>& bits, int k, int rawResp, bool exact) {\n        Query q;\n        q.bits = bits;\n        q.cells = cellIdx;\n        q.k = k;\n        q.exact = exact;\n\n        if (exact) {\n            q.obs = (double)rawResp;\n            q.w = 1e6; // very strong constraint\n        } else {\n            double coeff = 1.0 - 2.0 * eps;\n            double bias = (double)k * eps;\n            double est = (rawResp - bias) / coeff;\n            est = max(0.0, est);\n            est = min(est, (double)k * M);\n            q.obs = est;\n\n            double varx = (double)k * eps * (1.0 - eps);\n            // include rounding noise ~0.25 and small stabilizer\n            double vart = (varx + 0.25) / (coeff * coeff) + 1e-3;\n            q.w = 1.0 / vart;\n        }\n\n        queries.push_back(std::move(q));\n        int qid = (int)queries.size() - 1;\n\n        // append intersection counts for every placement\n        for (int f = 0; f < M; f++) {\n            for (auto &p: fields[f].ps) {\n                int c = popcountAnd(p.bits, queries[qid].bits);\n                p.inter.push_back((int16_t)c);\n            }\n        }\n    }\n\n    // --- query constructors ---\n    vector<int> cellsRow(int r) const {\n        vector<int> v; v.reserve(N);\n        for (int c = 0; c < N; c++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsCol(int c) const {\n        vector<int> v; v.reserve(N);\n        for (int r = 0; r < N; r++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsBlock(int r0, int r1, int c0, int c1) const {\n        vector<int> v;\n        for (int r = r0; r < r1; r++)\n            for (int c = c0; c < c1; c++)\n                v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsChecker(bool parity) const {\n        vector<int> v;\n        for (int r = 0; r < N; r++)\n            for (int c = 0; c < N; c++)\n                if (((r+c)&1) == (parity?1:0)) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> cellsRandomFixedSize(int k) {\n        vector<int> all(N2);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n        all.resize(max(2, k));\n        sort(all.begin(), all.end());\n        all.erase(unique(all.begin(), all.end()), all.end());\n        if ((int)all.size() < 2) {\n            all.clear();\n            all.push_back(0);\n            all.push_back(1);\n        }\n        return all;\n    }\n\n    vector<uint64_t> bitsFromCells(const vector<int>& v) const {\n        vector<uint64_t> b(L, 0ULL);\n        for (int idx: v) bitSet(b, idx);\n        return b;\n    }\n\n    // perform a divination query\n    void doDivination(const vector<int>& cellIdx) {\n        if ((int)cellIdx.size() < 2) return;\n        if (!canSpendOps(1)) return;\n\n        vector<pair<int,int>> out;\n        out.reserve(cellIdx.size());\n        for (int idx: cellIdx) out.push_back({idx / N, idx % N});\n        int y = divineCells(out);\n\n        vector<uint64_t> b = bitsFromCells(cellIdx);\n        addQuery(cellIdx, b, (int)cellIdx.size(), y, false);\n    }\n\n    // drill a cell and add exact constraint-query\n    void doDrill(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (!canSpendOps(1)) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<int> cellIdx = {idx};\n        vector<uint64_t> b(L, 0ULL);\n        bitSet(b, idx);\n        addQuery(cellIdx, b, 1, v, true);\n    }\n\n    // --- SA inference ---\n    Solution runSA(const vector<int>* startIdx, int iters) {\n        int Q = (int)queries.size();\n        vector<double> obs(Q), w(Q);\n        for (int q = 0; q < Q; q++) { obs[q] = queries[q].obs; w[q] = queries[q].w; }\n\n        vector<int> idx(M, 0);\n        if (startIdx) idx = *startIdx;\n        else {\n            for (int f = 0; f < M; f++) {\n                uniform_int_distribution<int> dist(0, (int)fields[f].ps.size() - 1);\n                idx[f] = dist(rng);\n            }\n        }\n\n        vector<int> pred(Q, 0);\n        vector<double> err(Q, 0.0);\n        // initialize err = pred - obs\n        for (int q = 0; q < Q; q++) err[q] = -obs[q];\n        for (int f = 0; f < M; f++) {\n            auto &pl = fields[f].ps[idx[f]];\n            for (int q = 0; q < Q; q++) {\n                int c = pl.inter[q];\n                pred[q] += c;\n                err[q] += c;\n            }\n        }\n        double cost = 0;\n        for (int q = 0; q < Q; q++) cost += w[q] * err[q] * err[q];\n\n        vector<int> bestIdx = idx;\n        double bestCost = cost;\n\n        double T0 = 2.0, T1 = 0.05;\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        uniform_int_distribution<int> fieldDist(0, M-1);\n\n        for (int it = 0; it < iters; it++) {\n            double t = (double)it / max(1, iters - 1);\n            double T = T0 * pow(T1 / T0, t);\n\n            int f = fieldDist(rng);\n            int cur = idx[f];\n            int nxt = cur;\n\n            auto &ps = fields[f].ps;\n            if (!ps[cur].neigh.empty() && ur(rng) < 0.6) {\n                // local neighbor\n                uniform_int_distribution<int> nd(0, (int)ps[cur].neigh.size() - 1);\n                nxt = ps[cur].neigh[nd(rng)];\n            } else {\n                uniform_int_distribution<int> pd(0, (int)ps.size() - 1);\n                nxt = pd(rng);\n            }\n            if (nxt == cur) continue;\n\n            double delta = 0.0;\n            auto &oldP = ps[cur];\n            auto &newP = ps[nxt];\n\n            for (int q = 0; q < Q; q++) {\n                int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                if (d == 0) continue;\n                double e = err[q];\n                delta += w[q] * (2.0 * e * d + 1.0 * d * d);\n            }\n\n            if (delta <= 0.0 || ur(rng) < exp(-delta / T)) {\n                // accept\n                for (int q = 0; q < Q; q++) {\n                    int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                    if (d == 0) continue;\n                    pred[q] += d;\n                    err[q] += d;\n                }\n                idx[f] = nxt;\n                cost += delta;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestIdx = idx;\n                }\n            }\n        }\n        return Solution{bestIdx, bestCost};\n    }\n\n    vector<Solution> sampleSolutions(int wantK) {\n        // SA restarts; keep best unique solutions\n        int restarts = 25;\n        int iters = 3500 + 30 * (int)queries.size();\n        iters = min(iters, 12000);\n\n        vector<Solution> sols;\n        sols.reserve(restarts);\n\n        // build a small pool of seeds from previous bests to stabilize (if any)\n        vector<vector<int>> seeds;\n        if (!sols.empty()) {\n            for (auto &s: sols) seeds.push_back(s.idx);\n        }\n\n        for (int r = 0; r < restarts; r++) {\n            vector<int> start;\n            bool useSeed = (!sols.empty() && (r % 5 == 0));\n            if (useSeed) {\n                start = sols[rng() % sols.size()].idx;\n                // random perturbation\n                for (int k = 0; k < 2; k++) {\n                    int f = rng() % M;\n                    int sz = (int)fields[f].ps.size();\n                    start[f] = rng() % sz;\n                }\n                auto res = runSA(&start, iters);\n                sols.push_back(std::move(res));\n            } else {\n                auto res = runSA(nullptr, iters);\n                sols.push_back(std::move(res));\n            }\n        }\n\n        sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b){ return a.cost < b.cost; });\n\n        unordered_set<uint64_t> seen;\n        vector<Solution> out;\n        for (auto &s: sols) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int x: s.idx) h = splitmix64(h ^ (uint64_t)x + 0x9e3779b97f4a7c15ULL);\n            if (seen.insert(h).second) out.push_back(s);\n            if ((int)out.size() >= wantK) break;\n        }\n        if (out.empty()) out.push_back(sols[0]);\n        return out;\n    }\n\n    // compute per-cell probability of being covered among given solutions\n    vector<double> computeCellProb(const vector<Solution>& sols) {\n        vector<int> cnt(N2, 0);\n        for (auto &s: sols) {\n            vector<uint64_t> uni(L, 0ULL);\n            for (int f = 0; f < M; f++) {\n                auto &pb = fields[f].ps[s.idx[f]].bits;\n                for (int t = 0; t < L; t++) uni[t] |= pb[t];\n            }\n            for (int idx = 0; idx < N2; idx++) {\n                if (bitGet(uni, idx)) cnt[idx]++;\n            }\n        }\n        vector<double> p(N2, 0.0);\n        for (int i = 0; i < N2; i++) p[i] = (double)cnt[i] / (double)sols.size();\n        // enforce drilled constraints (for decisions)\n        for (int i = 0; i < N2; i++) {\n            if (drilledVal[i] != -1) p[i] = (drilledVal[i] > 0) ? 1.0 : 0.0;\n        }\n        return p;\n    }\n\n    vector<pair<int,int>> buildAnswerFromProb(const vector<double>& p) const {\n        vector<pair<int,int>> ans;\n        ans.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            bool oil = (p[idx] >= 0.5);\n            if (drilledVal[idx] != -1) oil = (drilledVal[idx] > 0);\n            if (oil) ans.push_back({idx / N, idx % N});\n        }\n        return ans;\n    }\n\n    // --- main solve routine ---\n    void solve() {\n        // initial divinations (stop early if we must reserve operations)\n        // rows/cols\n        for (int i = 0; i < N; i++) doDivination(cellsRow(i));\n        for (int j = 0; j < N; j++) doDivination(cellsCol(j));\n\n        // blocks\n        int B = (N >= 18) ? 4 : (N >= 14) ? 3 : 2;\n        int step = (N + B - 1) / B;\n        for (int bi = 0; bi < B; bi++) {\n            for (int bj = 0; bj < B; bj++) {\n                int r0 = bi * step, r1 = min(N, (bi + 1) * step);\n                int c0 = bj * step, c1 = min(N, (bj + 1) * step);\n                auto v = cellsBlock(r0, r1, c0, c1);\n                if ((int)v.size() >= 2) doDivination(v);\n            }\n        }\n\n        // checkerboards\n        doDivination(cellsChecker(false));\n        doDivination(cellsChecker(true));\n\n        // random large subsets\n        int randQ = (N >= 16 ? 18 : 14);\n        for (int t = 0; t < randQ; t++) {\n            int k = (t % 2 == 0) ? (N2 / 2) : (N2 / 3);\n            doDivination(cellsRandomFixedSize(k));\n        }\n\n        // iterative: SA -> probabilities -> drill uncertain\n        int maxRounds = 6;\n        int totalDrillBudget = (N >= 16 ? 70 : 55);\n        int drilledThisPhase = 0;\n\n        for (int round = 0; round < maxRounds; round++) {\n            int wantK = 25;\n            auto sols = sampleSolutions(wantK);\n            auto prob = computeCellProb(sols);\n\n            // collect uncertain cells\n            const double pLow = 0.05, pHigh = 0.95;\n            vector<pair<double,int>> cand;\n            cand.reserve(N2);\n            for (int idx = 0; idx < N2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                double p = prob[idx];\n                if (pLow < p && p < pHigh) {\n                    cand.push_back({abs(p - 0.5), idx});\n                }\n            }\n            sort(cand.begin(), cand.end());\n\n            if (cand.empty()) {\n                // extra validation drills (small)\n                bool mismatch = false;\n                vector<pair<double,int>> zeroCand, oneCand;\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    double p = prob[idx];\n                    if (p <= pLow) zeroCand.push_back({-p, idx}); // closer to boundary first\n                    else if (p >= pHigh) oneCand.push_back({p, idx}); // smaller p first\n                }\n                sort(zeroCand.begin(), zeroCand.end());\n                sort(oneCand.begin(), oneCand.end());\n\n                int checks = 0;\n                for (int t = 0; t < (int)zeroCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = zeroCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] > 0) mismatch = true;\n                }\n                checks = 0;\n                for (int t = 0; t < (int)oneCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = oneCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] == 0) mismatch = true;\n                }\n                if (mismatch) continue;\n\n                // attempt answer (keeping fallback possible)\n                if (canSpendOps(1)) {\n                    auto ans = buildAnswerFromProb(prob);\n                    int ok = answerCells(ans);\n                    if (ok == 1) return;\n                    // if wrong, break to fallback\n                    break;\n                } else {\n                    break;\n                }\n            } else {\n                // drill the most uncertain cells (batch)\n                int batch = min(10, (int)cand.size());\n                for (int t = 0; t < batch; t++) {\n                    if (drilledThisPhase >= totalDrillBudget) break;\n                    if (!canSpendOps(1)) break;\n                    doDrill(cand[t].second);\n                    drilledThisPhase++;\n                }\n            }\n        }\n\n        // fallback: drill everything remaining, answer exactly\n        vector<pair<int,int>> oilCells;\n        oilCells.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] == -1) doDrill(idx);\n            if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n        }\n        (void)answerCells(oilCells);\n        return;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    double eps;\n    cin >> N >> M >> eps;\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; k++) {\n        int d;\n        cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; t++) {\n            int i, j;\n            cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    Solver solver(N, M, eps);\n    solver.buildPlacements(shapes);\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int WFIX = 1000;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) cin >> a[d][k];\n    }\n    // W is fixed at 1000 in the problem, but read anyway.\n    (void)W;\n\n    // We build a fixed partition into N horizontal stripes of full width 1000.\n    // Stripe k has height h[k] (positive int), sum(h)=1000, area=1000*h[k].\n    // Keep h sorted nondecreasing to match with sorted demands rank-wise.\n    vector<int> h(N, 1);\n    int remaining = WFIX - N; // extra height units to distribute\n\n    auto gain_if_increment = [&](int idx) -> long long {\n        // Benefit (reduction in total shortage over all days) if we increase h[idx] by 1,\n        // i.e. area increases by 1000.\n        long long A = 1LL * WFIX * h[idx];\n        long long g = 0;\n        for (int d = 0; d < D; d++) {\n            long long diff = (long long)a[d][idx] - A;\n            if (diff > 0) g += min(1LL * WFIX, diff); // reduction capped by 1000\n        }\n        return g;\n    };\n\n    // Greedy allocation under the constraint that h stays sorted:\n    // only indices that are the rightmost in their equal-height block can be incremented.\n    for (int it = 0; it < remaining; it++) {\n        int best = -1;\n        long long bestGain = -1;\n\n        for (int i = 0; i < N; i++) {\n            if (i + 1 < N && h[i] == h[i + 1]) continue; // not rightmost of this height\n            long long g = gain_if_increment(i);\n            if (g > bestGain) {\n                bestGain = g;\n                best = i;\n            }\n        }\n        if (best < 0) best = N - 1; // fallback (shouldn't happen)\n\n        // If everything has 0 gain, just put the remaining height into the largest stripe.\n        if (bestGain == 0) best = N - 1;\n\n        h[best]++;\n\n        // h remains sorted: best is rightmost of its block and either best==N-1 or h[best] <= h[best+1] after +1.\n        // (Because previously h[best] < h[best+1] if best+1 exists.)\n    }\n\n    // Sanity check: sum heights == 1000\n    {\n        long long sumh = 0;\n        for (int x : h) sumh += x;\n        if (sumh != WFIX) {\n            // As a safety measure (should not happen), fix last stripe.\n            int diff = (int)(WFIX - sumh);\n            h.back() += diff;\n        }\n    }\n\n    // Build rectangles in this sorted order: stripe k is [y, y+h[k]) x [0,1000).\n    // This also matches input order because a[d][k] is sorted by k.\n    struct Rect { int i0, j0, i1, j1; };\n    vector<Rect> rect(N);\n    int y = 0;\n    for (int k = 0; k < N; k++) {\n        rect[k] = Rect{y, 0, y + h[k], WFIX};\n        y += h[k];\n    }\n    // y should be 1000.\n\n    // Output the same rectangles for every day.\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            auto &r = rect[k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << \"\\n\";\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Action {\n    uint8_t m, p, q;\n    uint8_t idx[9];   // affected cell indices 0..80\n    uint32_t val[9];  // added values mod MOD\n};\n\nstruct Change {\n    int cnt = 0;\n    uint8_t cell[18];\n    uint32_t delta[18]; // net delta for that cell in Z_MOD\n};\n\nstatic inline uint32_t addmod(uint32_t a, uint32_t b) {\n    uint32_t s = a + b;\n    if (s >= MOD) s -= MOD;\n    return s;\n}\n\nstatic inline uint32_t submod(uint32_t a, uint32_t b) {\n    // a - b mod MOD\n    return (a >= b) ? (a - b) : (a + MOD - b);\n}\n\nstatic inline void add_delta(Change &chg, uint8_t c, uint32_t dv) {\n    if (dv == 0) return;\n    for (int i = 0; i < chg.cnt; i++) {\n        if (chg.cell[i] == c) {\n            chg.delta[i] = addmod(chg.delta[i], dv);\n            return;\n        }\n    }\n    chg.cell[chg.cnt] = c;\n    chg.delta[chg.cnt] = dv;\n    chg.cnt++;\n}\n\nstatic inline int64_t compute_change(\n    int oldId, int newId,\n    const vector<Action> &actions,\n    const array<uint32_t, 81> &res,\n    Change &chg\n) {\n    chg.cnt = 0;\n\n    if (oldId != -1) {\n        const auto &a = actions[oldId];\n        for (int k = 0; k < 9; k++) {\n            uint32_t v = a.val[k];\n            uint32_t neg = (v == 0) ? 0u : (MOD - v);\n            add_delta(chg, a.idx[k], neg);\n        }\n    }\n    if (newId != -1) {\n        const auto &a = actions[newId];\n        for (int k = 0; k < 9; k++) {\n            add_delta(chg, a.idx[k], a.val[k]);\n        }\n    }\n\n    int64_t dscore = 0;\n    for (int i = 0; i < chg.cnt; i++) {\n        uint8_t c = chg.cell[i];\n        uint32_t r = res[c];\n        uint32_t dv = chg.delta[i];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        dscore += (int64_t)nr - (int64_t)r;\n    }\n    return dscore;\n}\n\nstatic inline void apply_change(Change &chg, array<uint32_t,81> &res) {\n    for (int i = 0; i < chg.cnt; i++) {\n        uint8_t c = chg.cell[i];\n        uint32_t r = res[c];\n        uint32_t dv = chg.delta[i];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        res[c] = nr;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K; // expected 9,20,81\n\n    array<uint32_t, 81> a0{};\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            uint64_t x;\n            cin >> x;\n            a0[i*N + j] = (uint32_t)(x % MOD);\n        }\n    }\n\n    // stamps[m][i][j]\n    vector<array<uint32_t, 9>> stamps(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint64_t x;\n                cin >> x;\n                stamps[m][i*3 + j] = (uint32_t)(x % MOD);\n            }\n        }\n    }\n\n    // Precompute all actions: M * 7 * 7 = 980\n    vector<Action> actions;\n    actions.reserve(M * (N-2) * (N-2));\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action act;\n                act.m = (uint8_t)m;\n                act.p = (uint8_t)p;\n                act.q = (uint8_t)q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        int bi = p + i;\n                        int bj = q + j;\n                        act.idx[t] = (uint8_t)(bi * N + bj);\n                        act.val[t] = stamps[m][i*3 + j];\n                        t++;\n                    }\n                }\n                actions.push_back(act);\n            }\n        }\n    }\n    const int A = (int)actions.size();\n\n    // Initial state\n    array<uint32_t, 81> res = a0;\n    int64_t score = 0;\n    for (uint32_t v : res) score += v;\n\n    vector<int> ops(K, -1);\n\n    // RNG seed (fixed but input-dependent for diversity)\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 81; i++) seed = seed * 1000003ULL + res[i];\n    XorShift64 rng(seed);\n\n    // Greedy fill (only positive gains)\n    for (int slot = 0; slot < K; slot++) {\n        int bestId = -1;\n        int64_t bestGain = 0;\n        Change chg;\n        Change bestChg;\n\n        for (int id = 0; id < A; id++) {\n            int64_t d = compute_change(-1, id, actions, res, chg);\n            if (d > bestGain) {\n                bestGain = d;\n                bestId = id;\n                bestChg = chg;\n            }\n        }\n        if (bestId == -1) break;\n        ops[slot] = bestId;\n        apply_change(bestChg, res);\n        score += bestGain;\n    }\n\n    // Save best\n    int64_t bestScore = score;\n    vector<int> bestOps = ops;\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95; // seconds\n    const double T0 = 2.0e9;\n    const double T1 = 1.0e7;\n\n    // Simulated annealing\n    while (true) {\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - start).count();\n        if (elapsed >= TL) break;\n\n        double progress = elapsed / TL;\n        double T = T0 * pow(T1 / T0, progress);\n\n        int slot = rng.nextInt(K);\n        int oldId = ops[slot];\n\n        int newId;\n        // ~7.8% set empty, otherwise random action\n        if ((rng.nextU64() & 1023ull) < 80ull) newId = -1;\n        else newId = rng.nextInt(A);\n\n        if (newId == oldId) continue;\n\n        Change chg;\n        int64_t d = compute_change(oldId, newId, actions, res, chg);\n\n        bool accept = false;\n        if (d >= 0) {\n            accept = true;\n        } else {\n            double x = (double)d / T;\n            if (x > -20.0) { // otherwise prob ~ 0\n                double prob = exp(x);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (accept) {\n            apply_change(chg, res);\n            score += d;\n            ops[slot] = newId;\n\n            if (score > bestScore) {\n                bestScore = score;\n                bestOps = ops;\n            }\n        }\n    }\n\n    // Restore best before hill-climb\n    ops = bestOps;\n    res = a0;\n    score = 0;\n    for (uint32_t v : res) score += v;\n    for (int i = 0; i < K; i++) {\n        if (ops[i] == -1) continue;\n        Change chg;\n        (void)compute_change(-1, ops[i], actions, res, chg);\n        apply_change(chg, res);\n    }\n    score = 0;\n    for (uint32_t v : res) score += v;\n\n    // Final 1-opt hill-climb (a couple of passes)\n    for (int pass = 0; pass < 2; pass++) {\n        bool improved = false;\n        for (int slot = 0; slot < K; slot++) {\n            int oldId = ops[slot];\n\n            int bestNew = oldId;\n            int64_t bestD = 0;\n            Change bestChg, chg;\n\n            // Try empty\n            {\n                int64_t d = compute_change(oldId, -1, actions, res, chg);\n                if (d > bestD) {\n                    bestD = d;\n                    bestNew = -1;\n                    bestChg = chg;\n                }\n            }\n            // Try all actions\n            for (int id = 0; id < A; id++) {\n                if (id == oldId) continue;\n                int64_t d = compute_change(oldId, id, actions, res, chg);\n                if (d > bestD) {\n                    bestD = d;\n                    bestNew = id;\n                    bestChg = chg;\n                }\n            }\n\n            if (bestNew != oldId) {\n                apply_change(bestChg, res);\n                score += bestD;\n                ops[slot] = bestNew;\n                improved = true;\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestOps = ops;\n                }\n            }\n        }\n        if (!improved) break;\n    }\n\n    // Output best\n    vector<tuple<int,int,int>> out;\n    out.reserve(K);\n    for (int i = 0; i < K; i++) {\n        int id = bestOps[i];\n        if (id == -1) continue;\n        const auto &a = actions[id];\n        out.emplace_back((int)a.m, (int)a.p, (int)a.q);\n    }\n\n    cout << out.size() << \"\\n\";\n    for (auto &[m,p,q] : out) {\n        cout << m << \" \" << p << \" \" << q << \"\\n\";\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 5;\nstatic const int MAX_TURNS = 10000;\n\nstruct Solver {\n    int n;\n    int A[N][N];\n\n    // grid container id or -1\n    int grid[N][N];\n\n    // for each receiving row r: how many have been spawned so far (0..N)\n    int spawned[N];\n\n    // per dispatch-group row t: bitmask of dispatched indices (0..4)\n    int dispMask[N];\n    int dispatchedCount = 0;\n\n    // origin info for each container id\n    int origRow[N*N], origIdx[N*N];\n\n    struct Crane {\n        int r=0, c=0;\n        bool alive=true;\n        bool holding=false;\n        int held=-1;\n        bool large=false;\n    };\n\n    Crane cranes[N]; // 0 is large, 1..4 small\n\n    vector<string> out; // 5 strings\n    int turn = 0;\n\n    Solver(int n_, const vector<vector<int>>& Ain) : n(n_), out(N, \"\") {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) A[i][j] = Ain[i][j];\n        // origin map\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            origRow[A[i][j]] = i;\n            origIdx[A[i][j]] = j;\n        }\n        // init grid empty\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) grid[i][j] = -1;\n        for(int i=0;i<N;i++) spawned[i] = 0;\n        for(int i=0;i<N;i++) dispMask[i] = 0;\n\n        // init cranes\n        for(int i=0;i<N;i++){\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].alive = true;\n            cranes[i].holding = false;\n            cranes[i].held = -1;\n            cranes[i].large = (i==0);\n        }\n    }\n\n    int expIndex(int t) const {\n        for(int k=0;k<N;k++){\n            if(((dispMask[t] >> k) & 1) == 0) return k;\n        }\n        return N; // done\n    }\n\n    int expectedId(int t) const {\n        int k = expIndex(t);\n        if(k>=N) return -1;\n        return 5*t + k;\n    }\n\n    pair<int,int> findPos(int id) const {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j] == id) return {i,j};\n        }\n        return {-1,-1};\n    }\n\n    bool holdingCraneAt(int r, int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].holding && cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n\n    // allowed storage: any cell with col in [1..3], plus (row,0) only if spawned[row]==N (gate exhausted)\n    bool isAllowedStorageCell(int r, int c) const {\n        if(c==4) return false; // dispatch column not for storage\n        if(c==0 && spawned[r] < N) return false; // active receiving gate: don't block\n        return true;\n    }\n\n    int countAllowedStorageEmpty() const {\n        int cnt=0;\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j]!=-1) continue;\n            if(!isAllowedStorageCell(i,j)) continue;\n            // avoid dispatch col already excluded\n            cnt++;\n        }\n        return cnt;\n    }\n\n    int invCostIfDispatch(int id) const {\n        int t = id/5;\n        int idx = id%5;\n        int cost = 0;\n        for(int k=0;k<idx;k++){\n            if(((dispMask[t] >> k) & 1) == 0) cost++;\n        }\n        return cost;\n    }\n\n    pair<int,int> chooseStorageCellNearest(int sr, int sc) const {\n        int bestD = INT_MAX;\n        pair<int,int> best = {-1,-1};\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j]!=-1) continue;\n            if(!isAllowedStorageCell(i,j)) continue;\n            int d = abs(sr-i) + abs(sc-j);\n            if(d < bestD){\n                bestD = d;\n                best = {i,j};\n            }\n        }\n        return best;\n    }\n\n    void step(char actLarge){\n        if(turn >= MAX_TURNS) return;\n\n        // decide actions for all cranes\n        char act[N];\n        for(int k=0;k<N;k++){\n            if(k==0) act[k] = actLarge;\n            else act[k] = (turn==0 ? 'B' : '.'); // bomb small cranes immediately\n        }\n\n        for(int k=0;k<N;k++) out[k].push_back(act[k]);\n\n        // 1) receiving\n        for(int r=0;r<N;r++){\n            if(spawned[r] >= N) continue;\n            if(grid[r][0] != -1) continue;\n            if(holdingCraneAt(r,0)) continue;\n            grid[r][0] = A[r][spawned[r]];\n            spawned[r]++;\n        }\n\n        // 2) actions simultaneously (generic, though after turn0 only crane0 alive)\n        // compute destinations\n        pair<int,int> startPos[N], destPos[N];\n        bool willBomb[N];\n        for(int k=0;k<N;k++){\n            startPos[k] = {cranes[k].r, cranes[k].c};\n            willBomb[k] = false;\n            destPos[k] = startPos[k];\n            if(!cranes[k].alive){\n                // must be '.'\n                continue;\n            }\n            char a = act[k];\n            if(a=='B'){\n                // bomb allowed only if not holding\n                if(cranes[k].holding){\n                    // illegal, but avoid WA in judge by doing nothing (should not happen)\n                    a='.';\n                } else {\n                    willBomb[k] = true;\n                }\n            } else if(a=='U' || a=='D' || a=='L' || a=='R'){\n                int nr = cranes[k].r;\n                int nc = cranes[k].c;\n                if(a=='U') nr--;\n                if(a=='D') nr++;\n                if(a=='L') nc--;\n                if(a=='R') nc++;\n                // bounds\n                if(0 <= nr && nr < N && 0 <= nc && nc < N){\n                    // small crane carrying restriction\n                    if(!cranes[k].large && cranes[k].holding){\n                        if(grid[nr][nc] != -1){\n                            // illegal, cancel move\n                            nr = cranes[k].r;\n                            nc = cranes[k].c;\n                        }\n                    }\n                    destPos[k] = {nr,nc};\n                }\n            }\n        }\n\n        // collision check after move among non-bombed alive cranes\n        // treat bombed cranes as removed\n        {\n            map<pair<int,int>, int> occ;\n            for(int k=0;k<N;k++){\n                if(!cranes[k].alive) continue;\n                if(willBomb[k]) continue;\n                auto d = destPos[k];\n                if(occ.count(d)){\n                    // invalid; in this solution it shouldn't happen (single crane after turn0)\n                    // resolve by forcing this crane to stay\n                    destPos[k] = startPos[k];\n                } else occ[d] = k;\n            }\n        }\n        // swap check\n        for(int i=0;i<N;i++) for(int j=i+1;j<N;j++){\n            if(!cranes[i].alive || !cranes[j].alive) continue;\n            if(willBomb[i] || willBomb[j]) continue;\n            if(destPos[i]==startPos[j] && destPos[j]==startPos[i] && destPos[i]!=destPos[j]){\n                // invalid swap; avoid by stopping j\n                destPos[j] = startPos[j];\n            }\n        }\n\n        // apply moves\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(willBomb[k]) continue;\n            cranes[k].r = destPos[k].first;\n            cranes[k].c = destPos[k].second;\n        }\n\n        // apply non-move actions (P/Q/B) (movement-only already applied)\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a = act[k];\n            if(a=='B'){\n                if(!cranes[k].holding){\n                    cranes[k].alive = false;\n                }\n            } else if(a=='P'){\n                int r = cranes[k].r, c = cranes[k].c;\n                if(!cranes[k].holding && grid[r][c] != -1){\n                    cranes[k].holding = true;\n                    cranes[k].held = grid[r][c];\n                    grid[r][c] = -1;\n                }\n            } else if(a=='Q'){\n                int r = cranes[k].r, c = cranes[k].c;\n                if(cranes[k].holding && grid[r][c] == -1){\n                    grid[r][c] = cranes[k].held;\n                    cranes[k].holding = false;\n                    cranes[k].held = -1;\n                }\n            }\n        }\n\n        // 3) dispatch\n        for(int r=0;r<N;r++){\n            if(grid[r][4] != -1){\n                int id = grid[r][4];\n                grid[r][4] = -1;\n                // mark dispatched\n                int t = id/5;\n                int idx = id%5;\n                if(((dispMask[t] >> idx) & 1) == 0){\n                    dispMask[t] |= (1<<idx);\n                    dispatchedCount++;\n                } else {\n                    // should not happen (duplicate dispatch), ignore\n                }\n            }\n        }\n\n        turn++;\n    }\n\n    void moveTo(int tr, int tc){\n        while(turn < MAX_TURNS && cranes[0].alive && (cranes[0].r != tr || cranes[0].c != tc)){\n            int r = cranes[0].r, c = cranes[0].c;\n            if(r < tr) step('D');\n            else if(r > tr) step('U');\n            else if(c < tc) step('R');\n            else if(c > tc) step('L');\n        }\n    }\n\n    void dispatchId(int id){\n        auto p = findPos(id);\n        if(p.first == -1) return; // not on grid (not spawned yet)\n        // go pick\n        moveTo(p.first, p.second);\n        // ensure container still here\n        if(turn >= MAX_TURNS) return;\n        if(cranes[0].holding) return;\n        if(grid[cranes[0].r][cranes[0].c] != id) return;\n        step('P');\n        if(turn >= MAX_TURNS) return;\n        // go to correct dispatch gate\n        int t = id/5;\n        moveTo(t, 4);\n        if(turn >= MAX_TURNS) return;\n        step('Q'); // dispatched in same turn end\n    }\n\n    void storeHeldToSomewhere(){\n        if(!cranes[0].holding) return;\n        auto s = chooseStorageCellNearest(cranes[0].r, cranes[0].c);\n        if(s.first == -1) return; // no space\n        moveTo(s.first, s.second);\n        if(turn >= MAX_TURNS) return;\n        step('Q');\n    }\n\n    void clearOneFromGate(int r){\n        // go to (r,0) and remove the current gate container by dispatching if good else storing/dispatching\n        moveTo(r, 0);\n        if(turn >= MAX_TURNS) return;\n\n        if(grid[r][0] == -1){\n            // maybe wait a turn for spawn if any\n            step('.');\n            return;\n        }\n        if(cranes[0].holding) return;\n        int id = grid[r][0];\n\n        step('P');\n        if(turn >= MAX_TURNS) return;\n        id = cranes[0].held;\n\n        int t = id/5;\n        int idx = id%5;\n        int e = expIndex(t);\n\n        int empty = countAllowedStorageEmpty();\n\n        // If it's exactly next expected for its group -> dispatch now\n        if(idx == e){\n            moveTo(t, 4);\n            if(turn >= MAX_TURNS) return;\n            step('Q');\n            return;\n        }\n\n        // If storage is available, store; otherwise dispatch out-of-order to free space\n        if(empty >= 2){\n            storeHeldToSomewhere();\n        } else {\n            moveTo(t, 4);\n            if(turn >= MAX_TURNS) return;\n            step('Q');\n        }\n    }\n\n    int chooseBestOutOfOrderDispatchCandidate() const {\n        // choose container on grid minimizing (invCost, distance, bonus for being at active gate)\n        int bestId = -1;\n        long long bestScore = (1LL<<60);\n        int cr = cranes[0].r, cc = cranes[0].c;\n\n        for(int i=0;i<N;i++) for(int j=0;j<4;j++){ // never any container at col4 in our sim\n            int id = grid[i][j];\n            if(id == -1) continue;\n            int inv = invCostIfDispatch(id);\n            int t = id/5;\n            int dist = abs(cr-i)+abs(cc-j) + abs(i-t)+abs(j-4);\n            long long score = 100000LL*inv + 10LL*dist;\n\n            // bonus: freeing an active gate is useful\n            if(j==0 && spawned[i] < N) score -= 50;\n\n            if(score < bestScore){\n                bestScore = score;\n                bestId = id;\n            }\n        }\n        return bestId;\n    }\n\n    int chooseExpectedToUncover() const {\n        // pick an expected container not yet on grid, whose origin needs fewest clears\n        int bestD = -1;\n        pair<int,int> bestKey = {INT_MAX, INT_MAX};\n        int cr = cranes[0].r, cc = cranes[0].c;\n\n        for(int t=0;t<N;t++){\n            int d = expectedId(t);\n            if(d == -1) continue; // group done\n            auto p = findPos(d);\n            if(p.first != -1) continue; // already on grid\n\n            int r = origRow[d];\n            int oi = origIdx[d];\n\n            // spawned[r] is #spawned so far (0..5).\n            // If d not spawned yet, oi >= spawned[r].\n            int needClears = 0;\n            if(spawned[r] <= oi) needClears = oi - spawned[r] + 1;\n            else needClears = 0; // already spawned, should be on grid, but handle\n\n            int distGate = abs(cr-r)+abs(cc-0);\n            pair<int,int> key = {needClears, distGate};\n            if(key < bestKey){\n                bestKey = key;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\n    void run(){\n        // Turn 0: spawn first containers and bomb small cranes\n        step('.');\n\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            // 1) if any expected container exists on grid, dispatch it (choose nearest)\n            int bestExpId = -1;\n            int bestDist = INT_MAX;\n            int cr = cranes[0].r, cc = cranes[0].c;\n\n            for(int t=0;t<N;t++){\n                int d = expectedId(t);\n                if(d == -1) continue;\n                auto p = findPos(d);\n                if(p.first == -1) continue;\n                int dist = abs(cr-p.first) + abs(cc-p.second) + abs(p.first - t) + abs(p.second - 4);\n                if(dist < bestDist){\n                    bestDist = dist;\n                    bestExpId = d;\n                }\n            }\n\n            if(bestExpId != -1){\n                dispatchId(bestExpId);\n                continue;\n            }\n\n            // 2) if storage is tight, dispatch something (min extra inversions)\n            int empty = countAllowedStorageEmpty();\n            if(empty <= 1){\n                int cand = chooseBestOutOfOrderDispatchCandidate();\n                if(cand != -1){\n                    dispatchId(cand);\n                    continue;\n                }\n            }\n\n            // 3) otherwise, try to uncover some expected container by clearing its origin gate\n            int d = chooseExpectedToUncover();\n            if(d != -1){\n                int r = origRow[d];\n                clearOneFromGate(r);\n                continue;\n            }\n\n            // 4) fallback: dispatch any remaining container\n            int any = -1;\n            for(int i=0;i<N;i++) for(int j=0;j<4;j++){\n                if(grid[i][j] != -1){ any = grid[i][j]; break; }\n            }\n            if(any != -1){\n                dispatchId(any);\n            } else {\n                step('.');\n            }\n        }\n\n        // If somehow not finished, continue brute-force dispatching until time limit.\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            int any = -1;\n            for(int i=0;i<N;i++) for(int j=0;j<4;j++){\n                if(grid[i][j] != -1){ any = grid[i][j]; break; }\n            }\n            if(any != -1) dispatchId(any);\n            else step('.');\n        }\n\n        // Ensure output length >= 1\n        if(turn == 0) step('.');\n    }\n\n    void print() const {\n        for(int i=0;i<N;i++){\n            cout << out[i] << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<vector<int>> A(n, vector<int>(n));\n    for(int i=0;i<n;i++){\n        for(int j=0;j<n;j++) cin >> A[i][j];\n    }\n\n    Solver solver(n, A);\n    solver.run();\n    solver.print();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF = (1LL<<62);\n\nstruct Candidate {\n    long long cost = INF;\n    int kind = -1; // 0 = cycle, 1 = tree\n    // for cycle\n    vector<int> cycle_order; // size 400, starts with 0\n    long long cycle_L0 = 0;\n\n    // for tree\n    vector<int> parent; // size 400\n    vector<vector<int>> child_order; // rooted children order\n    long long tree_borrow = 0;\n};\n\nstruct Emitter {\n    vector<string> ops;\n    void emit_move(char c) { ops.emplace_back(1, c); }\n    void emit_amount(char sign, long long d) {\n        while (d > 0) {\n            long long x = min(d, 1000000LL);\n            ops.push_back(string(1, sign) + to_string(x));\n            d -= x;\n        }\n    }\n};\n\nstatic inline int id(int r, int c, int N){ return r*N + c; }\nstatic inline int r_of(int v, int N){ return v / N; }\nstatic inline int c_of(int v, int N){ return v % N; }\n\nstatic inline char move_dir(int from, int to, int N){\n    int fr = r_of(from, N), fc = c_of(from, N);\n    int tr = r_of(to, N), tc = c_of(to, N);\n    if (tr == fr-1 && tc == fc) return 'U';\n    if (tr == fr+1 && tc == fc) return 'D';\n    if (tr == fr && tc == fc-1) return 'L';\n    if (tr == fr && tc == fc+1) return 'R';\n    // should never happen\n    return '?';\n}\n\nvector<int> gen_cycle_reserve_col0(int N){\n    // Construction:\n    // (0,0)->(1,0)->...->(N-1,0),\n    // then snake through columns 1..N-1 from bottom row to top row,\n    // ending at (0,1), which is adjacent to (0,0).\n    vector<int> v;\n    v.reserve(N*N);\n    v.push_back(id(0,0,N));\n    for(int r=1;r<N;r++) v.push_back(id(r,0,N));\n    for(int r=N-1;r>=0;r--){\n        int t = (N-1 - r) & 1;\n        if(t==0){\n            for(int c=1;c<N;c++) v.push_back(id(r,c,N));\n        }else{\n            for(int c=N-1;c>=1;c--) v.push_back(id(r,c,N));\n        }\n    }\n    // size should be N^2\n    return v;\n}\n\nvector<int> gen_cycle_reserve_row0(int N){\n    // Diagonal-symmetric version:\n    // traverse row0 left->right, then snake columns downward/upward through rows 1..N-1,\n    // ending at (1,0), adjacent to (0,0).\n    vector<int> v;\n    v.reserve(N*N);\n    for(int c=0;c<N;c++) v.push_back(id(0,c,N));\n    for(int c=N-1;c>=0;c--){\n        int t = (N-1 - c) & 1;\n        if(t==0){\n            for(int r=1;r<N;r++) v.push_back(id(r,c,N));\n        }else{\n            for(int r=N-1;r>=1;r--) v.push_back(id(r,c,N));\n        }\n    }\n    return v;\n}\n\n// Evaluate Hamiltonian cycle order (vector size 400, order[0]=0)\n// Traversal is order[0]->order[1]->...->order[399]->order[0]\npair<long long,long long> eval_cycle(const vector<int>& order, const vector<int>& h) {\n    // Compute minimal L0 so that along visiting order[1..399], prefix load never goes negative,\n    // and also L0 >= h[0] if h[0] > 0 to have enough soil overall.\n    long long cum = 0, minPref = 0;\n    for(int i=1;i<(int)order.size();i++){\n        cum += h[order[i]];\n        minPref = min(minPref, cum);\n    }\n    long long h00 = h[0];\n    long long L0 = max({0LL, h00, -minPref});\n\n    long long load = L0;\n    long long cost = 0;\n\n    // initial load at (0,0)\n    cost += L0;\n\n    // traverse 400 moves\n    for(int step=0; step<400; step++){\n        cost += 100 + load;\n        int nxt = order[(step+1)%400];\n        if(step == 399) break; // returned to start, do not process start here\n        int hh = h[nxt];\n        cost += llabs((long long)hh);\n        load += hh;\n        if(load < 0) return {INF, L0}; // infeasible (shouldn't happen)\n    }\n    // final unload remaining load into (0,0)\n    cost += load;\n    return {cost, L0};\n}\n\nvector<int> reversed_cycle_order(const vector<int>& base){\n    // base[0] must be 0\n    vector<int> o(400);\n    o[0] = 0;\n    for(int i=1;i<400;i++){\n        o[i] = base[400 - i]; // base[399],...,base[1]\n    }\n    return o;\n}\n\nvoid build_ops_cycle(const vector<int>& order, const vector<int>& h, int N, long long L0, vector<string>& out_ops){\n    Emitter em;\n    long long load = 0;\n\n    if(L0 > 0){\n        em.emit_amount('+', L0);\n        load += L0;\n    }\n\n    int cur = order[0];\n    for(int step=0; step<400; step++){\n        int nxt = order[(step+1)%400];\n        char dir = move_dir(cur, nxt, N);\n        em.emit_move(dir);\n        cur = nxt;\n\n        if(step == 399) break; // back to start\n        int hh = h[cur];\n        if(hh > 0){\n            em.emit_amount('+', hh);\n            load += hh;\n        }else if(hh < 0){\n            em.emit_amount('-', - (long long)hh);\n            load += hh;\n        }\n    }\n\n    if(load > 0){\n        em.emit_amount('-', load);\n        load = 0;\n    }\n\n    out_ops = std::move(em.ops);\n}\n\n// Build children list from parent array\nvector<vector<int>> build_children(const vector<int>& parent){\n    int V = (int)parent.size();\n    vector<vector<int>> ch(V);\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        if(p >= 0) ch[p].push_back(v);\n    }\n    return ch;\n}\n\n// Compute subtree (req, gain) and a good child order for each node.\n// Root is 0. Root has no exit requirement (we fix it by final unload).\nstruct Task { long long req, gain; int child; };\n\nstruct TreeDPResult {\n    vector<long long> req;\n    vector<long long> gain;\n    vector<vector<int>> child_order;\n    long long root_borrow = 0;\n};\n\nTreeDPResult compute_tree_dp(const vector<vector<int>>& children, const vector<int>& h){\n    int V = (int)children.size();\n    TreeDPResult res;\n    res.req.assign(V, 0);\n    res.gain.assign(V, 0);\n    res.child_order.assign(V, {});\n\n    function<void(int)> dfs = [&](int v){\n        for(int c: children[v]) dfs(c);\n\n        vector<Task> tasks;\n        tasks.reserve(children[v].size());\n        long long sum_children = 0;\n        for(int c: children[v]){\n            tasks.push_back(Task{res.req[c], res.gain[c], c});\n            sum_children += res.gain[c];\n        }\n\n        auto cmp = [&](const Task& a, const Task& b){\n            bool ap = (a.gain >= 0);\n            bool bp = (b.gain >= 0);\n            if(ap && bp) return a.req < b.req;\n            if(ap != bp) return ap > bp; // positive gain first\n            // both negative gain: sort by (req - gain) descending\n            return (a.req - a.gain) > (b.req - b.gain);\n        };\n        sort(tasks.begin(), tasks.end(), cmp);\n\n        res.child_order[v].clear();\n        for(auto &t: tasks) res.child_order[v].push_back(t.child);\n\n        // minimal required balance to run child tasks in this order\n        long long bal = 0, need = 0;\n        for(auto &t: tasks){\n            need = max(need, t.req - bal);\n            bal += t.gain;\n        }\n        // bal == sum_children\n\n        if(v == 0){\n            long long e = max(0, h[v]); // loaded at start\n            long long borrow = max(0LL, need - e);\n            res.root_borrow = borrow;\n            res.req[v] = borrow;\n            res.gain[v] = (long long)h[v] + sum_children;\n        }else{\n            long long e = max(0, h[v]); // loaded on entry\n            long long exit_req = max(0, -h[v]); // must have enough before unloading at exit\n            long long r = 0;\n            r = max(r, need - e);\n            r = max(r, exit_req - e - sum_children);\n\n            long long g = (long long)h[v] + sum_children;\n            if(g < 0) r = max(r, -g); // must not end with negative load\n            r = max(r, 0LL);\n\n            res.req[v] = r;\n            res.gain[v] = g;\n        }\n    };\n\n    dfs(0);\n    return res;\n}\n\n// Evaluate a rooted spanning tree solution (Euler tour, entry-load positives, exit-unload negatives)\npair<long long, TreeDPResult> eval_tree(const vector<int>& parent, const vector<int>& h, int N){\n    int V = N*N;\n    auto children = build_children(parent);\n    auto dp = compute_tree_dp(children, h);\n\n    long long borrow = dp.root_borrow;\n    long long startLoad = max(0, h[0]) + borrow;\n\n    long long load = startLoad;\n    long long cost = 0;\n\n    // initial load\n    cost += startLoad;\n\n    vector<pair<int,int>> st;\n    st.reserve(V);\n    st.push_back({0, 0});\n\n    while(!st.empty()){\n        int v = st.back().first;\n        int &idx = st.back().second;\n\n        if(idx < (int)dp.child_order[v].size()){\n            int c = dp.child_order[v][idx++];\n            // move v -> c\n            cost += 100 + load;\n\n            // entry at child: if positive, load it\n            if(h[c] > 0){\n                cost += h[c];\n                load += h[c];\n            }\n\n            st.push_back({c, 0});\n        }else{\n            // exit v: if negative (and not root), unload it now\n            if(v != 0 && h[v] < 0){\n                long long need = - (long long)h[v];\n                if(load < need) return {INF, dp}; // infeasible\n                cost += need;\n                load -= need;\n            }\n            st.pop_back();\n            if(st.empty()) break;\n            int p = st.back().first;\n            // move v -> p\n            cost += 100 + load;\n        }\n    }\n\n    // final unload all remaining load at root\n    cost += load;\n    return {cost, dp};\n}\n\nvoid build_ops_tree(const vector<int>& parent, const TreeDPResult& dp, const vector<int>& h, int N, vector<string>& out_ops){\n    Emitter em;\n\n    long long borrow = dp.root_borrow;\n    long long startLoad = max(0, h[0]) + borrow;\n\n    long long load = 0;\n    if(startLoad > 0){\n        em.emit_amount('+', startLoad);\n        load += startLoad;\n    }\n\n    vector<pair<int,int>> st;\n    st.reserve(N*N);\n    st.push_back({0, 0});\n\n    while(!st.empty()){\n        int v = st.back().first;\n        int &idx = st.back().second;\n\n        if(idx < (int)dp.child_order[v].size()){\n            int c = dp.child_order[v][idx++];\n            // move v->c\n            em.emit_move(move_dir(v, c, N));\n\n            // entry op at c\n            if(h[c] > 0){\n                em.emit_amount('+', h[c]);\n                load += h[c];\n            }\n            st.push_back({c, 0});\n        }else{\n            // exit op at v\n            if(v != 0 && h[v] < 0){\n                long long need = - (long long)h[v];\n                // should be feasible\n                em.emit_amount('-', need);\n                load -= need;\n            }\n            st.pop_back();\n            if(st.empty()) break;\n            int p = st.back().first;\n            em.emit_move(move_dir(v, p, N));\n        }\n    }\n\n    if(load > 0){\n        em.emit_amount('-', load);\n        load = 0;\n    }\n\n    out_ops = std::move(em.ops);\n}\n\nvector<int> bfs_tree(int N, vector<int> neigh_order){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0] = 1;\n    parent[0] = -1;\n\n    while(!q.empty()){\n        int v = q.front(); q.pop();\n        int r = r_of(v, N), c = c_of(v, N);\n        // fixed 4-neighborhood but in specified order indices (0..3)\n        // 0:U 1:D 2:L 3:R\n        for(int t: neigh_order){\n            int nr=r, nc=c;\n            if(t==0) nr--;\n            if(t==1) nr++;\n            if(t==2) nc--;\n            if(t==3) nc++;\n            if(nr<0||nr>=N||nc<0||nc>=N) continue;\n            int u = id(nr,nc,N);\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    // should visit all\n    return parent;\n}\n\nvector<int> random_dfs_tree(int N, std::mt19937_64& rng){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    vector<int> st;\n    st.reserve(V);\n    st.push_back(0);\n    vis[0] = 1;\n    parent[0] = -1;\n\n    while(!st.empty()){\n        int v = st.back();\n        int r = r_of(v, N), c = c_of(v, N);\n\n        int cand[4];\n        int cc = 0;\n        if(r>0) { int u=id(r-1,c,N); if(!vis[u]) cand[cc++]=u; }\n        if(r+1<N) { int u=id(r+1,c,N); if(!vis[u]) cand[cc++]=u; }\n        if(c>0) { int u=id(r,c-1,N); if(!vis[u]) cand[cc++]=u; }\n        if(c+1<N) { int u=id(r,c+1,N); if(!vis[u]) cand[cc++]=u; }\n\n        if(cc==0){\n            st.pop_back();\n        }else{\n            std::uniform_int_distribution<int> dist(0, cc-1);\n            int u = cand[dist(rng)];\n            vis[u]=1;\n            parent[u]=v;\n            st.push_back(u);\n        }\n    }\n    return parent;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<int> h(N*N);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin >> h[id(i,j,N)];\n        }\n    }\n\n    Candidate best;\n\n    // ---- Cycle candidates ----\n    {\n        vector<vector<int>> bases;\n        bases.push_back(gen_cycle_reserve_col0(N));\n        bases.push_back(gen_cycle_reserve_row0(N));\n\n        for(auto &base: bases){\n            if((int)base.size() != N*N) continue;\n            // forward\n            {\n                auto [cost, L0] = eval_cycle(base, h);\n                if(cost < best.cost){\n                    best.cost = cost;\n                    best.kind = 0;\n                    best.cycle_order = base;\n                    best.cycle_L0 = L0;\n                }\n            }\n            // reverse\n            {\n                auto rev = reversed_cycle_order(base);\n                auto [cost, L0] = eval_cycle(rev, h);\n                if(cost < best.cost){\n                    best.cost = cost;\n                    best.kind = 0;\n                    best.cycle_order = rev;\n                    best.cycle_L0 = L0;\n                }\n            }\n        }\n    }\n\n    // ---- Deterministic tree candidates ----\n    {\n        vector<vector<int>> neigh_orders = {\n            {3,1,2,0}, // R,D,L,U\n            {1,3,2,0}, // D,R,L,U\n            {3,2,1,0}, // R,L,D,U\n        };\n        for(auto &ord: neigh_orders){\n            auto parent = bfs_tree(N, ord);\n            auto [cost, dp] = eval_tree(parent, h, N);\n            if(cost < best.cost){\n                best.cost = cost;\n                best.kind = 1;\n                best.parent = parent;\n                best.child_order = dp.child_order;\n                best.tree_borrow = dp.root_borrow;\n            }\n        }\n    }\n\n    // ---- Randomized tree search (time-limited) ----\n    {\n        std::mt19937_64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n        auto t0 = chrono::steady_clock::now();\n        int iters = 0;\n\n        while(true){\n            iters++;\n            if(iters > 2000) break;\n            auto now = chrono::steady_clock::now();\n            double sec = chrono::duration<double>(now - t0).count();\n            if(sec > 1.70) break; // keep margin for output building\n\n            auto parent = random_dfs_tree(N, rng);\n            auto [cost, dp] = eval_tree(parent, h, N);\n            if(cost < best.cost){\n                best.cost = cost;\n                best.kind = 1;\n                best.parent = parent;\n                best.child_order = dp.child_order;\n                best.tree_borrow = dp.root_borrow;\n            }\n        }\n    }\n\n    // ---- Build and output operations for best ----\n    vector<string> ops;\n    if(best.kind == 0){\n        build_ops_cycle(best.cycle_order, h, N, best.cycle_L0, ops);\n    }else{\n        // Recompute DP to ensure consistency if needed\n        auto children = build_children(best.parent);\n        auto dp = compute_tree_dp(children, h);\n        build_ops_tree(best.parent, dp, h, N, ops);\n    }\n\n    // Safety: must be <= 100000 turns\n    if((int)ops.size() > 100000){\n        // Fallback: output nothing (will be heavily penalized, but avoids invalid)\n        // In practice this won't happen with our constructions.\n        ops.clear();\n    }\n\n    for(auto &s: ops) cout << s << \"\\n\";\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int INF_INT = 1e9;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ull;\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int n) { // [0,n)\n        return (int)(nextU64() % (uint64_t)n);\n    }\n};\n\nstruct Seed {\n    array<uint8_t, 15> x{};\n    int V = 0;\n    int peak = 0;\n};\n\nstatic inline int diffCount(const Seed& a, const Seed& b, int M) {\n    int d = 0;\n    for (int i = 0; i < M; i++) d += (a.x[i] != b.x[i]);\n    return d;\n}\n\nstatic inline int potentialSumMax(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += max<int>(a.x[i], b.x[i]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60\n\n    vector<Seed> seeds(SEED_COUNT);\n\n    auto readSeeds = [&]() {\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int sum = 0, pk = 0;\n            for (int l = 0; l < M; l++) {\n                int v;\n                cin >> v;\n                seeds[k].x[l] = (uint8_t)v;\n                sum += v;\n                pk = max(pk, v);\n            }\n            seeds[k].V = sum;\n            seeds[k].peak = pk;\n        }\n    };\n\n    readSeeds();\n\n    // Precompute grid neighbors and degrees.\n    const int P = N * N; // 36\n    vector<vector<int>> neigh(P);\n    vector<pair<int,int>> edges;\n    vector<int> degree(P, 0);\n    auto id = [&](int i, int j){ return i * N + j; };\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int v = id(i,j);\n            if (i > 0) neigh[v].push_back(id(i-1,j));\n            if (i + 1 < N) neigh[v].push_back(id(i+1,j));\n            if (j > 0) neigh[v].push_back(id(i,j-1));\n            if (j + 1 < N) neigh[v].push_back(id(i,j+1));\n            degree[v] = (int)neigh[v].size();\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j + 1 < N; j++) edges.push_back({id(i,j), id(i,j+1)});\n    }\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j < N; j++) edges.push_back({id(i,j), id(i+1,j)});\n    }\n\n    vector<int> posOrder(P);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (degree[a] != degree[b]) return degree[a] > degree[b];\n        return a < b;\n    });\n\n    RNG rng;\n    auto startTime = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.90; // safety vs 2.0\n\n    for (int t = 0; t < T; t++) {\n        // Time allocation for this turn\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - startTime).count();\n        double remaining = max(0.0, TIME_LIMIT - elapsed);\n        double perTurn = remaining / max(1, (T - t));\n        auto turnStart = now;\n        auto turnEnd = turnStart + chrono::duration<double>(perTurn * 0.95);\n\n        // ---- 1) select 36 seeds ----\n        vector<int> idx(SEED_COUNT);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (seeds[a].V != seeds[b].V) return seeds[a].V > seeds[b].V;\n            return a < b;\n        });\n\n        const int eliteCount = 8;\n        vector<int> selected;\n        selected.reserve(P);\n        vector<char> used(SEED_COUNT, 0);\n        vector<char> protectedSeed(SEED_COUNT, 0);\n\n        auto addSeed = [&](int k, bool protect=false) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n            if (protect) protectedSeed[k] = 1;\n        };\n\n        // Elites\n        for (int i = 0; i < eliteCount; i++) addSeed(idx[i], true);\n\n        // Similar partner for each elite (preservation)\n        for (int i = 0; i < eliteCount; i++) {\n            int e = idx[i];\n            int best = -1;\n            int bestScore = INF_INT;\n            for (int j = 0; j < SEED_COUNT; j++) if (j != e) {\n                if (used[j]) continue;\n                int d = diffCount(seeds[e], seeds[j], M);\n                int vd = abs(seeds[e].V - seeds[j].V);\n                // prioritize similarity strongly, but avoid extremely low-value partner\n                int score = d * 100 + vd;\n                if (score < bestScore) {\n                    bestScore = score;\n                    best = j;\n                } else if (score == bestScore && seeds[j].V > seeds[best].V) {\n                    best = j;\n                }\n            }\n            if (best != -1) addSeed(best, true);\n        }\n\n        // Per-dimension top candidates\n        const int perDimTake = 2;\n        for (int l = 0; l < M; l++) {\n            vector<int> ord(SEED_COUNT);\n            iota(ord.begin(), ord.end(), 0);\n            nth_element(ord.begin(), ord.begin() + min(SEED_COUNT, 12), ord.end(), [&](int a, int b){\n                if (seeds[a].x[l] != seeds[b].x[l]) return seeds[a].x[l] > seeds[b].x[l];\n                return seeds[a].V > seeds[b].V;\n            });\n            // Just scan best few (cheap)\n            sort(ord.begin(), ord.begin() + min(SEED_COUNT, 12), [&](int a, int b){\n                if (seeds[a].x[l] != seeds[b].x[l]) return seeds[a].x[l] > seeds[b].x[l];\n                return seeds[a].V > seeds[b].V;\n            });\n            int taken = 0;\n            for (int z = 0; z < min(SEED_COUNT, 12) && taken < perDimTake; z++) {\n                int k = ord[z];\n                if (!used[k]) {\n                    addSeed(k, false);\n                    taken++;\n                }\n            }\n        }\n\n        // Fill remaining by mixed score\n        auto mixedScore = [&](int k) -> double {\n            return (double)seeds[k].V + 0.8 * (double)seeds[k].peak;\n        };\n        vector<int> rest;\n        rest.reserve(SEED_COUNT);\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        sort(rest.begin(), rest.end(), [&](int a, int b){\n            double sa = mixedScore(a), sb = mixedScore(b);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n        for (int k : rest) {\n            if ((int)selected.size() >= P) break;\n            addSeed(k, false);\n        }\n\n        // If too many (can happen due to per-dimension), prune non-protected\n        if ((int)selected.size() > P) {\n            auto importance = [&](int k) -> double {\n                return (double)seeds[k].V + 0.3 * (double)seeds[k].peak;\n            };\n            // collect removable\n            vector<int> removable;\n            for (int k : selected) if (!protectedSeed[k]) removable.push_back(k);\n            sort(removable.begin(), removable.end(), [&](int a, int b){\n                double ia = importance(a), ib = importance(b);\n                if (ia != ib) return ia < ib; // remove low importance first\n                return a > b;\n            });\n            int ptr = 0;\n            while ((int)selected.size() > P && ptr < (int)removable.size()) {\n                int rm = removable[ptr++];\n                // remove rm from selected\n                auto it = find(selected.begin(), selected.end(), rm);\n                if (it != selected.end()) selected.erase(it);\n            }\n            // If still too many (unlikely), drop from end\n            while ((int)selected.size() > P) selected.pop_back();\n        }\n\n        // ---- 2) placement via SA ----\n\n        // Local indexing for selected seeds\n        vector<int> globOfLocal(P);\n        for (int i = 0; i < P; i++) globOfLocal[i] = selected[i];\n\n        // Pair score matrix among selected (local indices)\n        double phase = (T == 1) ? 1.0 : (double)t / (double)(T - 1); // 0..1\n        double lambda = 2.0 + 3.0 * phase; // similarity penalty increases over time\n        double rho    = 0.05 + 0.45 * phase; // robustness term increases over time\n\n        vector<vector<double>> pairScore(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            pairScore[i][i] = 0.0;\n            for (int j = i + 1; j < P; j++) {\n                const Seed& A = seeds[globOfLocal[i]];\n                const Seed& B = seeds[globOfLocal[j]];\n                int pot = potentialSumMax(A, B, M);\n                int d = diffCount(A, B, M);\n                int mn = min(A.V, B.V);\n                double s = (double)pot + rho * (double)mn - lambda * (double)d;\n                pairScore[i][j] = pairScore[j][i] = s;\n            }\n        }\n\n        // Initial permutation: high-importance seeds to high-degree positions\n        vector<int> localOrder(P);\n        iota(localOrder.begin(), localOrder.end(), 0);\n        sort(localOrder.begin(), localOrder.end(), [&](int a, int b){\n            int ga = globOfLocal[a], gb = globOfLocal[b];\n            double sa = (double)seeds[ga].V + 0.5 * (double)seeds[ga].peak;\n            double sb = (double)seeds[gb].V + 0.5 * (double)seeds[gb].peak;\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        vector<int> perm(P, 0); // perm[pos] = local seed index\n        for (int k = 0; k < P; k++) {\n            perm[posOrder[k]] = localOrder[k];\n        }\n\n        auto evalObjective = [&]() -> double {\n            double s = 0.0;\n            for (auto [u, v] : edges) {\n                s += pairScore[perm[u]][perm[v]];\n            }\n            return s;\n        };\n\n        double cur = evalObjective();\n        double best = cur;\n        vector<int> bestPerm = perm;\n\n        // SA parameters\n        const double tempStart = 500.0;\n        const double tempEnd = 10.0;\n\n        auto getTemp = [&](double prog) -> double {\n            // geometric cooling\n            double r = tempEnd / tempStart;\n            return tempStart * pow(r, prog);\n        };\n\n        while (chrono::steady_clock::now() < turnEnd) {\n            int a = rng.nextInt(P);\n            int b = rng.nextInt(P);\n            if (a == b) continue;\n\n            int la = perm[a];\n            int lb = perm[b];\n            double delta = 0.0;\n\n            for (int na : neigh[a]) {\n                if (na == b) continue;\n                int lx = perm[na];\n                delta -= pairScore[la][lx];\n                delta += pairScore[lb][lx];\n            }\n            for (int nb : neigh[b]) {\n                if (nb == a) continue;\n                int lx = perm[nb];\n                delta -= pairScore[lb][lx];\n                delta += pairScore[la][lx];\n            }\n\n            auto now2 = chrono::steady_clock::now();\n            double prog = chrono::duration<double>(now2 - turnStart).count() /\n                          max(1e-9, chrono::duration<double>(turnEnd - turnStart).count());\n            prog = min(1.0, max(0.0, prog));\n            double temp = getTemp(prog);\n\n            bool accept = false;\n            if (delta >= 0) {\n                accept = true;\n            } else {\n                double p = exp(delta / temp);\n                if (rng.nextDouble() < p) accept = true;\n            }\n\n            if (accept) {\n                swap(perm[a], perm[b]);\n                cur += delta;\n                if (cur > best) {\n                    best = cur;\n                    bestPerm = perm;\n                }\n            }\n        }\n\n        perm = bestPerm;\n\n        // ---- Output layout ----\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = id(i,j);\n                int localIdx = perm[pos];\n                int globalIdx = globOfLocal[localIdx];\n                if (j) cout << ' ';\n                cout << globalIdx;\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        // ---- Read next generation ----\n        readSeeds();\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n};\n\nstatic const int dx4[4] = {0, 1, 0, -1}; // R, D, L, U\nstatic const int dy4[4] = {1, 0, -1, 0};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    vector<vector<int>> cur(N, vector<int>(N, 0));\n    vector<vector<int>> target(N, vector<int>(N, 0));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cur[i][j] = (s[i][j] == '1');\n            target[i][j] = (t[i][j] == '1');\n        }\n    }\n\n    // Build surplus and deficit lists.\n    vector<Pos> surplus, deficit;\n    surplus.reserve(N*N);\n    deficit.reserve(N*N);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (cur[i][j] == 1 && target[i][j] == 0) surplus.push_back({i,j});\n        if (cur[i][j] == 0 && target[i][j] == 1) deficit.push_back({i,j});\n    }\n\n    // Design: V'=2, edge (0->1) length 1, root initial position (0,0).\n    const int Vp = 2;\n\n    // State\n    int rx = 0, ry = 0; // root\n    int dir = 0;        // 0:R 1:D 2:L 3:U ; initial edges extend to the right => R\n    bool holding = false;\n\n    vector<string> ops;\n    ops.reserve(100000);\n\n    auto inside = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    };\n\n    auto rotStep = [&](int curDir, int toDir) -> char {\n        int cw = (toDir - curDir + 4) % 4;\n        int ccw = (curDir - toDir + 4) % 4;\n        if (cw <= ccw) return 'R';\n        else return 'L';\n    };\n\n    auto applyTurn = [&](char mv, char rot, bool wantP) {\n        // decide actual action legality after move/rot\n        // Build command string of length 2*Vp = 4:\n        // [0]=move, [1]=rot of vertex1, [2]=action of v0, [3]=action of v1\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        cmd[1] = rot;\n        cmd[2] = '.';\n\n        // Apply movement (root must remain inside)\n        int nrx = rx, nry = ry;\n        if (mv == 'U') nrx--;\n        else if (mv == 'D') nrx++;\n        else if (mv == 'L') nry--;\n        else if (mv == 'R') nry++;\n\n        if (mv != '.') {\n            if (inside(nrx, nry)) {\n                rx = nrx; ry = nry;\n            } else {\n                // should not happen with our planning; output '.' instead\n                cmd[0] = '.';\n            }\n        }\n\n        // Apply rotation\n        if (rot == 'L') dir = (dir + 3) % 4;\n        else if (rot == 'R') dir = (dir + 1) % 4;\n        else cmd[1] = '.';\n\n        // Action after move/rot\n        char actChar = '.';\n        int gx = rx + dx4[dir];\n        int gy = ry + dy4[dir];\n        if (wantP && inside(gx, gy)) {\n            if (!holding) {\n                // pick only if cell has takoyaki and it's not a target cell (we avoid harming correct ones)\n                if (cur[gx][gy] == 1 && target[gx][gy] == 0) {\n                    cur[gx][gy] = 0;\n                    holding = true;\n                    actChar = 'P';\n                }\n            } else {\n                // place only if empty and it's a target cell\n                if (cur[gx][gy] == 0 && target[gx][gy] == 1) {\n                    cur[gx][gy] = 1;\n                    holding = false;\n                    actChar = 'P';\n                }\n            }\n        }\n        cmd[3] = actChar;\n\n        ops.push_back(std::move(cmd));\n    };\n\n    // Move root to (tx,ty) and orient dir to tdir, using Manhattan path;\n    // rotate simultaneously during moves when possible.\n    auto moveRootAndOrient = [&](int tx, int ty, int tdir, bool doActionAtEnd) {\n        vector<pair<char,char>> steps;\n\n        int cx = rx, cy = ry;\n        int cdir = dir;\n\n        auto pushStep = [&](char mv) {\n            char rot = '.';\n            if (cdir != tdir) {\n                rot = rotStep(cdir, tdir);\n                if (rot == 'L') cdir = (cdir + 3) % 4;\n                else if (rot == 'R') cdir = (cdir + 1) % 4;\n            }\n            // update root pos in local simulation\n            if (mv == 'U') cx--;\n            else if (mv == 'D') cx++;\n            else if (mv == 'L') cy--;\n            else if (mv == 'R') cy++;\n            steps.push_back({mv, rot});\n        };\n\n        // Horizontal then vertical (any fixed order is fine)\n        while (cy < ty) pushStep('R');\n        while (cy > ty) pushStep('L');\n        while (cx < tx) pushStep('D');\n        while (cx > tx) pushStep('U');\n\n        // Remaining rotations\n        while (cdir != tdir) {\n            char rot = rotStep(cdir, tdir);\n            if (rot == 'L') cdir = (cdir + 3) % 4;\n            else cdir = (cdir + 1) % 4;\n            steps.push_back({'.', rot});\n        }\n\n        if (doActionAtEnd) {\n            if (steps.empty()) steps.push_back({'.','.'});\n            for (int i = 0; i < (int)steps.size(); i++) {\n                bool wantP = (i + 1 == (int)steps.size());\n                applyTurn(steps[i].first, steps[i].second, wantP);\n            }\n        } else {\n            for (auto [mv, rot] : steps) applyTurn(mv, rot, false);\n        }\n    };\n\n    // Make fingertip land on cell (x,y), optionally do pick/place there at the end.\n    auto goFingerToCell = [&](int x, int y, bool doActionAtEnd) {\n        // Candidate (root position, dir) such that root + dir == (x,y)\n        int bestTurns = INT_MAX;\n        int bestRx = rx, bestRy = ry, bestDir = dir;\n\n        for (int d = 0; d < 4; d++) {\n            int rrx = x - dx4[d];\n            int rry = y - dy4[d];\n            if (!inside(rrx, rry)) continue;\n\n            int dist = abs(rx - rrx) + abs(ry - rry);\n            int cw = (d - dir + 4) % 4;\n            int ccw = (dir - d + 4) % 4;\n            int rotCost = min(cw, ccw);\n            int turns = max(dist, rotCost); // rotation can be overlapped with movement\n            // tie-breakers: smaller dist, smaller rotCost\n            if (turns < bestTurns ||\n                (turns == bestTurns && dist < abs(rx - bestRx) + abs(ry - bestRy)) ||\n                (turns == bestTurns && dist == abs(rx - bestRx) + abs(ry - bestRy) && rotCost < min((bestDir-dir+4)%4,(dir-bestDir+4)%4))) {\n                bestTurns = turns;\n                bestRx = rrx;\n                bestRy = rry;\n                bestDir = d;\n            }\n        }\n\n        // Move and orient\n        moveRootAndOrient(bestRx, bestRy, bestDir, doActionAtEnd);\n    };\n\n    // Main greedy transport loop\n    while (!deficit.empty() && !surplus.empty() && (int)ops.size() < 100000) {\n        // Choose closest pair\n        int bi = -1, bj = -1;\n        int best = INT_MAX;\n        for (int i = 0; i < (int)surplus.size(); i++) {\n            for (int j = 0; j < (int)deficit.size(); j++) {\n                int d = abs(surplus[i].x - deficit[j].x) + abs(surplus[i].y - deficit[j].y);\n                if (d < best) {\n                    best = d;\n                    bi = i; bj = j;\n                }\n            }\n        }\n        if (bi < 0) break;\n\n        Pos src = surplus[bi];\n        Pos dst = deficit[bj];\n\n        // Go pick at src\n        goFingerToCell(src.x, src.y, true);\n        if (!holding) {\n            // If something went wrong (shouldn't), skip this source by removing it to avoid infinite loop\n            surplus[bi] = surplus.back();\n            surplus.pop_back();\n            continue;\n        }\n\n        // Go drop at dst\n        goFingerToCell(dst.x, dst.y, true);\n        if (holding) {\n            // failed to drop (shouldn't), stop to keep output legal and bounded\n            break;\n        }\n\n        // Update lists: remove used src and dst\n        surplus[bi] = surplus.back();\n        surplus.pop_back();\n        deficit[bj] = deficit.back();\n        deficit.pop_back();\n    }\n\n    // Output arm design\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\";\n    cout << 0 << \" \" << 0 << \"\\n\"; // initial root position\n\n    // Output operations\n    for (auto &cmd : ops) cout << cmd << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXC = 100000;\nstatic constexpr int MAXC1 = 100001; // MAXC + 1\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed = 0) {\n        if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Pt {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Rect {\n    int x1, x2, y1, y2; // inclusive bounds, require x1 < x2, y1 < y2\n};\n\nstatic inline int binCoord(int v, int G) {\n    // v in [0..100000], map to [0..G-1]\n    // Using MAXC1=100001 so that 100000 maps to G-1.\n    long long b = (long long)v * G / MAXC1;\n    if (b < 0) b = 0;\n    if (b >= G) b = G - 1;\n    return (int)b;\n}\n\nstatic inline long long perimeter2(const Rect& r) {\n    // actual perimeter = 2*(dx+dy)\n    long long dx = r.x2 - r.x1;\n    long long dy = r.y2 - r.y1;\n    return 2LL * (dx + dy);\n}\n\nstatic int evalDiff(const vector<Pt>& pts, const Rect& r) {\n    int s = 0;\n    for (const auto &p : pts) {\n        if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) s += p.w;\n    }\n    return s;\n}\n\nstatic bool containsAny(const vector<Pt>& pts, const Rect& r) {\n    for (const auto &p : pts) {\n        if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N; // fixed 5000 in all tests\n    vector<Pt> pts;\n    pts.reserve(2 * N);\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n        int w = (i < N ? +1 : -1);\n        pts.push_back({x, y, w});\n    }\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    // --- 1) Coarse grid max-sum subrectangle ---\n    const int G = 200;\n    vector<int> bx(G + 1), by(G + 1);\n    for (int i = 0; i <= G; i++) {\n        bx[i] = (int)((long long)i * MAXC1 / G);\n        by[i] = (int)((long long)i * MAXC1 / G);\n    }\n    // bx[G]=by[G]=100001\n\n    vector<vector<int>> grid(G, vector<int>(G, 0));\n    for (auto &p : pts) {\n        int gx = binCoord(p.x, G);\n        int gy = binCoord(p.y, G);\n        grid[gy][gx] += p.w;\n    }\n\n    int bestSum = INT_MIN;\n    int bestL = 0, bestR = 0, bestB = 0, bestT = 0;\n\n    vector<int> colSum(G);\n    for (int L = 0; L < G; L++) {\n        fill(colSum.begin(), colSum.end(), 0);\n        for (int R = L; R < G; R++) {\n            for (int y = 0; y < G; y++) colSum[y] += grid[y][R];\n\n            // Kadane on colSum\n            int cur = 0;\n            int curStart = 0;\n            int localBest = INT_MIN;\n            int localB = 0, localT = 0;\n\n            for (int y = 0; y < G; y++) {\n                if (cur <= 0) {\n                    cur = colSum[y];\n                    curStart = y;\n                } else {\n                    cur += colSum[y];\n                }\n                if (cur > localBest) {\n                    localBest = cur;\n                    localB = curStart;\n                    localT = y;\n                }\n            }\n\n            if (localBest > bestSum) {\n                bestSum = localBest;\n                bestL = L; bestR = R;\n                bestB = localB; bestT = localT;\n            }\n        }\n    }\n\n    auto rectFromGrid = [&](int L, int R, int B, int T) -> Rect {\n        int x1 = bx[L];\n        int x2 = bx[R + 1] - 1;\n        int y1 = by[B];\n        int y2 = by[T + 1] - 1;\n        x1 = max(0, min(MAXC, x1));\n        x2 = max(0, min(MAXC, x2));\n        y1 = max(0, min(MAXC, y1));\n        y2 = max(0, min(MAXC, y2));\n        if (x2 <= x1) x2 = min(MAXC, x1 + 1);\n        if (y2 <= y1) y2 = min(MAXC, y1 + 1);\n        return Rect{x1, x2, y1, y2};\n    };\n\n    Rect curR = rectFromGrid(bestL, bestR, bestB, bestT);\n    int curDiff = evalDiff(pts, curR);\n\n    Rect bestRct = curR;\n    int bestDiff = curDiff;\n\n    // --- 2) Some random rectangle sampling (cheap multi-start boost) ---\n    auto clampi = [&](int v) { return max(0, min(MAXC, v)); };\n    auto tryUpdate = [&](const Rect& r) {\n        if (!(r.x1 < r.x2 && r.y1 < r.y2)) return;\n        if (perimeter2(r) > 400000) return;\n        int d = evalDiff(pts, r);\n        if (d > bestDiff) {\n            bestDiff = d;\n            bestRct = r;\n        }\n    };\n\n    // Random rectangles centered around random points (tends to hit clusters)\n    for (int it = 0; it < 200; it++) {\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size() - 1)];\n        int wx = rng.nextInt(200, 20000);\n        int wy = rng.nextInt(200, 20000);\n        int x1 = clampi(p.x - wx);\n        int x2 = clampi(p.x + wx);\n        int y1 = clampi(p.y - wy);\n        int y2 = clampi(p.y + wy);\n        if (x2 <= x1) x2 = min(MAXC, x1 + 1);\n        if (y2 <= y1) y2 = min(MAXC, y1 + 1);\n        tryUpdate(Rect{x1, x2, y1, y2});\n    }\n\n    // start SA from current best\n    curR = bestRct;\n    curDiff = bestDiff;\n\n    // --- 3) Candidate coordinate lists for SA refinement ---\n    vector<int> candX, candY;\n    candX.reserve(2000);\n    candY.reserve(2000);\n    auto addCand = [&](vector<int>& v, int c) {\n        if (0 <= c && c <= MAXC) v.push_back(c);\n    };\n\n    addCand(candX, 0); addCand(candX, MAXC);\n    addCand(candY, 0); addCand(candY, MAXC);\n\n    // Add point-based candidates (x, x\u00b11), random sample\n    int samples = 600;\n    for (int i = 0; i < samples; i++) {\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size() - 1)];\n        addCand(candX, p.x); addCand(candX, p.x - 1); addCand(candX, p.x + 1);\n        addCand(candY, p.y); addCand(candY, p.y - 1); addCand(candY, p.y + 1);\n    }\n    // Also add current boundaries and neighbors\n    for (int d = -3; d <= 3; d++) {\n        addCand(candX, curR.x1 + d);\n        addCand(candX, curR.x2 + d);\n        addCand(candY, curR.y1 + d);\n        addCand(candY, curR.y2 + d);\n    }\n\n    sort(candX.begin(), candX.end());\n    candX.erase(unique(candX.begin(), candX.end()), candX.end());\n    sort(candY.begin(), candY.end());\n    candY.erase(unique(candY.begin(), candY.end()), candY.end());\n\n    // --- 4) Simulated annealing on rectangle sides ---\n    auto startTime = chrono::high_resolution_clock::now();\n    const double TIME_LIMIT = 1.85; // seconds (keep margin)\n    const double T0 = 30.0;\n    const double T1 = 0.5;\n\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - startTime).count();\n    };\n\n    int iters = 0;\n    while (true) {\n        double t = elapsedSec();\n        if (t > TIME_LIMIT) break;\n        double prog = t / TIME_LIMIT;\n        double T = T0 * pow(T1 / T0, prog);\n\n        Rect nxt = curR;\n        int side = rng.nextInt(0, 3); // 0:L 1:R 2:B 3:T\n\n        if (side == 0) { // left\n            int nx1 = candX[rng.nextInt(0, (int)candX.size() - 1)];\n            if (nx1 >= nxt.x2) { iters++; continue; }\n            nxt.x1 = nx1;\n        } else if (side == 1) { // right\n            int nx2 = candX[rng.nextInt(0, (int)candX.size() - 1)];\n            if (nx2 <= nxt.x1) { iters++; continue; }\n            nxt.x2 = nx2;\n        } else if (side == 2) { // bottom\n            int ny1 = candY[rng.nextInt(0, (int)candY.size() - 1)];\n            if (ny1 >= nxt.y2) { iters++; continue; }\n            nxt.y1 = ny1;\n        } else { // top\n            int ny2 = candY[rng.nextInt(0, (int)candY.size() - 1)];\n            if (ny2 <= nxt.y1) { iters++; continue; }\n            nxt.y2 = ny2;\n        }\n\n        if (perimeter2(nxt) > 400000) { iters++; continue; }\n\n        int nd = evalDiff(pts, nxt);\n        int delta = nd - curDiff;\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curR = nxt;\n            curDiff = nd;\n            if (curDiff > bestDiff) {\n                bestDiff = curDiff;\n                bestRct = curR;\n            }\n        }\n        iters++;\n    }\n\n    // If somehow bestDiff < 0, output an empty small rectangle (diff=0 => score 1)\n    if (bestDiff < 0) {\n        Rect empty{0, 1, 0, 1};\n        for (int tries = 0; tries < 2000; tries++) {\n            int x1 = rng.nextInt(0, MAXC - 1);\n            int y1 = rng.nextInt(0, MAXC - 1);\n            Rect r{x1, x1 + 1, y1, y1 + 1};\n            if (!containsAny(pts, r)) { empty = r; break; }\n        }\n        bestRct = empty;\n        bestDiff = 0;\n    }\n\n    // Final sanity\n    if (!(bestRct.x1 < bestRct.x2 && bestRct.y1 < bestRct.y2)) {\n        // fallback\n        bestRct = Rect{0, 1, 0, 1};\n    }\n    if (perimeter2(bestRct) > 400000) {\n        // should not happen, but clamp as fallback\n        bestRct = Rect{0, 100000, 0, 100000};\n    }\n\n    // Output rectangle as orthogonal simple polygon (4 vertices), all distinct.\n    cout << 4 << \"\\n\";\n    cout << bestRct.x1 << \" \" << bestRct.y1 << \"\\n\";\n    cout << bestRct.x2 << \" \" << bestRct.y1 << \"\\n\";\n    cout << bestRct.x2 << \" \" << bestRct.y2 << \"\\n\";\n    cout << bestRct.x1 << \" \" << bestRct.y2 << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Plan {\n    vector<Op> ops;\n    long long predW = (1LL<<62);\n    long long predH = (1LL<<62);\n    long long predScore = (1LL<<62);\n    string tag;\n};\n\nstatic inline pair<long long,long long> dims(const vector<long long>& w, const vector<long long>& h, int i, int r){\n    if(r==0) return {w[i], h[i]};\n    return {h[i], w[i]};\n}\n\nstatic inline int rot_wide_minheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=max(w,h) and height=min(w,h)\n    return (w[i] < h[i]) ? 1 : 0;\n}\nstatic inline int rot_narrow_maxheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=min(w,h) and height=max(w,h)\n    return (w[i] > h[i]) ? 1 : 0;\n}\n\nPlan make_single_row(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r = (rotMode==0 ? rot_wide_minheight(w,h,i) : rot_narrow_maxheight(w,h,i));\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'L',-1});\n        W += ww;\n        H = max(H, hh);\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_row_wide\" : \"single_row_narrow\");\n    return pl;\n}\n\nPlan make_single_col(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r;\n        if(rotMode==0){\n            // minimize width\n            r = (w[i] > h[i]) ? 1 : 0;\n        }else{\n            // minimize height (often worse for columns but add diversity)\n            r = (w[i] < h[i]) ? 1 : 0;\n        }\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'U',-1});\n        W = max(W, ww);\n        H += hh;\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_col_minW\" : \"single_col_minH\");\n    return pl;\n}\n\n// Contiguous shelf rows with width limit M (simple fallback/diversity).\nPlan make_shelf_rows_width_limit(const vector<long long>& w, const vector<long long>& h, long long M){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n\n    long long totalH = 0;\n    long long maxW = 0;\n\n    int prevRowRep = -1;\n    long long curW = 0;\n    long long curH = 0;\n    int curRep = -1;\n\n    auto close_row = [&](){\n        if(curRep==-1) return;\n        totalH += curH;\n        maxW = max(maxW, curW);\n        prevRowRep = curRep;\n        curW = 0;\n        curH = 0;\n        curRep = -1;\n    };\n\n    for(int i=0;i<N;i++){\n        // try both rotations\n        auto [w0,h0] = dims(w,h,i,0);\n        auto [w1,h1] = dims(w,h,i,1);\n        bool fit0 = (curRep==-1 ? (w0<=M || curW==0) : (curW + w0 <= M));\n        bool fit1 = (curRep==-1 ? (w1<=M || curW==0) : (curW + w1 <= M));\n\n        int r = -1;\n        if(curRep==-1){\n            // new row: choose smaller height\n            if(h0 < h1) r=0; else r=1;\n        }else{\n            if(fit0 && fit1){\n                // choose smaller resulting row height, tie by smaller width\n                long long nh0 = max(curH, h0), nh1 = max(curH, h1);\n                if(nh0 != nh1) r = (nh0 < nh1 ? 0 : 1);\n                else r = (w0 < w1 ? 0 : 1);\n            }else if(fit0) r=0;\n            else if(fit1) r=1;\n        }\n\n        if(curRep!=-1 && r==-1){\n            close_row();\n            // new row, pick smaller height\n            if(h0 < h1) r=0; else r=1;\n        }\n\n        auto [ww,hh] = dims(w,h,i,r);\n        int b = (prevRowRep==-1 ? -1 : prevRowRep);\n        pl.ops.push_back({i,r,'L',b});\n        curW += ww;\n        if(hh > curH){\n            curH = hh;\n            curRep = i;\n        }else if(curRep==-1){\n            curRep = i;\n        }\n    }\n    close_row();\n\n    pl.predW = maxW;\n    pl.predH = totalH;\n    pl.predScore = pl.predW + pl.predH;\n    pl.tag = \"shelf_rows_M=\" + to_string(M);\n    return pl;\n}\n\n// Fixed prefix headers 0..m-1 in top row, then greedy assign remaining to columns.\n// Requires each assigned rectangle width <= its column width, otherwise infeasible.\nPlan make_prefix_columns_bruteforce(const vector<long long>& w, const vector<long long>& h, int m){\n    int N = (int)w.size();\n    Plan best;\n    best.predScore = (1LL<<62);\n    if(m<=0 || m> N) return best;\n\n    int lim = 1<<m;\n    vector<int> bestHeaderRot(m,0);\n    vector<int> bestCol(N,-1), bestRot(N,0);\n\n    for(int mask=0; mask<lim; mask++){\n        vector<long long> colW(m), colH(m);\n        long long totalW = 0;\n        long long maxH = 0;\n        for(int j=0;j<m;j++){\n            int r = (mask>>j)&1;\n            auto [ww,hh] = dims(w,h,j,r);\n            colW[j]=ww; colH[j]=hh;\n            totalW += ww;\n            maxH = max(maxH, hh);\n        }\n\n        vector<int> colOf(N,-1), rotOf(N,0);\n        for(int j=0;j<m;j++){\n            colOf[j]=j;\n            rotOf[j]= (mask>>j)&1;\n        }\n\n        bool ok = true;\n        for(int i=m;i<N;i++){\n            long long bestObj = (1LL<<62);\n            int bestJ=-1, bestR=0;\n            for(int j=0;j<m;j++){\n                for(int r=0;r<=1;r++){\n                    auto [ww,hh] = dims(w,h,i,r);\n                    if(ww > colW[j]) continue;\n                    long long nh = colH[j] + hh;\n                    long long nMaxH = max(maxH, nh);\n                    long long obj = totalW + nMaxH;\n                    if(obj < bestObj || (obj==bestObj && nh < colH[bestJ] + dims(w,h,i,bestR).second)){\n                        bestObj=obj;\n                        bestJ=j; bestR=r;\n                    }\n                }\n            }\n            if(bestJ==-1){\n                ok=false; break;\n            }\n            auto [ww,hh] = dims(w,h,i,bestR);\n            colH[bestJ] += hh;\n            maxH = max(maxH, colH[bestJ]);\n            colOf[i]=bestJ;\n            rotOf[i]=bestR;\n        }\n        if(!ok) continue;\n\n        long long score = totalW + maxH;\n        if(score < best.predScore){\n            best.predScore = score;\n            best.predW = totalW;\n            best.predH = maxH;\n            best.ops.clear();\n            best.ops.reserve(N);\n\n            // build operations: headers L, others U with b = header of left column\n            // column j starts at right edge of header (j-1) (or x=0 if j=0)\n            for(int i=0;i<N;i++){\n                int r = rotOf[i];\n                if(i < m){\n                    best.ops.push_back({i,r,'L',-1});\n                }else{\n                    int cj = colOf[i];\n                    int b = (cj==0 ? -1 : (cj-1)); // header index (cj-1) because headers are 0..m-1\n                    best.ops.push_back({i,r,'U',b});\n                }\n            }\n            best.tag = \"prefix_cols_bruteforce_m=\" + to_string(m);\n        }\n    }\n    return best;\n}\n\n// Online columns: open new columns as needed/beneficial. Columns are disjoint by enforcing width<=colWidth.\nPlan make_online_columns(const vector<long long>& w, const vector<long long>& h,\n                         long long openBias, int headerMode, std::mt19937_64* rng = nullptr)\n{\n    int N = (int)w.size();\n    struct Col{ long long W,H; int headerIdx; };\n    vector<Col> cols;\n    vector<Op> ops;\n    ops.reserve(N);\n\n    long long totalW = 0;\n    long long maxH = 0;\n\n    auto chooseHeaderRot = [&](int i)->int{\n        if(headerMode==0) return rot_wide_minheight(w,h,i);\n        else return rot_narrow_maxheight(w,h,i);\n    };\n\n    for(int i=0;i<N;i++){\n        if(cols.empty()){\n            int r = chooseHeaderRot(i);\n            auto [ww,hh] = dims(w,h,i,r);\n            cols.push_back({ww,hh,i});\n            totalW += ww;\n            maxH = max(maxH, hh);\n            ops.push_back({i,r,'L',-1});\n            continue;\n        }\n\n        // best existing placement\n        long long bestObj = (1LL<<62);\n        int bestC = -1, bestR = 0;\n        for(int c=0;c<(int)cols.size();c++){\n            for(int r=0;r<=1;r++){\n                auto [ww,hh] = dims(w,h,i,r);\n                if(ww > cols[c].W) continue;\n                long long nh = cols[c].H + hh;\n                long long nMaxH = max(maxH, nh);\n                long long obj = totalW + nMaxH;\n                if(obj < bestObj){\n                    bestObj = obj;\n                    bestC = c;\n                    bestR = r;\n                }else if(obj == bestObj && rng){\n                    // random tie-break to diversify\n                    if(((*rng)() & 7ULL)==0ULL){\n                        bestC = c;\n                        bestR = r;\n                    }\n                }\n            }\n        }\n\n        // open new column option (always feasible)\n        int hr = chooseHeaderRot(i);\n        auto [wNew,hNew] = dims(w,h,i,hr);\n        long long openObj = (totalW + wNew) + max(maxH, hNew) + openBias;\n\n        bool doOpen = false;\n        if(bestC==-1) doOpen = true;\n        else if(openObj < bestObj) doOpen = true;\n\n        if(doOpen){\n            cols.push_back({wNew,hNew,i});\n            totalW += wNew;\n            maxH = max(maxH, hNew);\n            ops.push_back({i,hr,'L',-1});\n        }else{\n            auto [ww,hh] = dims(w,h,i,bestR);\n            cols[bestC].H += hh;\n            maxH = max(maxH, cols[bestC].H);\n            int b = (bestC==0 ? -1 : cols[bestC-1].headerIdx);\n            ops.push_back({i,bestR,'U',b});\n        }\n    }\n\n    Plan pl;\n    pl.ops = std::move(ops);\n    pl.predW = totalW;\n    pl.predH = maxH;\n    pl.predScore = totalW + maxH;\n    pl.tag = string(\"online_cols_bias=\") + to_string(openBias) + (headerMode==0 ? \"_wide\" : \"_narrow\");\n    return pl;\n}\n\nstatic uint64_t hash_plan_ops(const vector<Op>& ops){\n    // lightweight hash to drop exact duplicates\n    uint64_t x = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v){\n        x ^= v;\n        x *= 1099511628211ULL;\n    };\n    for(const auto& op: ops){\n        mix((uint64_t)op.p);\n        mix((uint64_t)op.r);\n        mix((uint64_t)op.d);\n        mix((uint64_t)(op.b + 2)); // shift\n    }\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    cin >> N >> T >> sigma;\n    vector<long long> w(N), h(N);\n    for(int i=0;i<N;i++) cin >> w[i] >> h[i];\n\n    mt19937_64 rng(123456789ULL);\n\n    vector<Plan> plans;\n\n    // Baselines\n    plans.push_back(make_single_row(w,h,0));\n    plans.push_back(make_single_row(w,h,1));\n    plans.push_back(make_single_col(w,h,0));\n    plans.push_back(make_single_col(w,h,1));\n\n    // Shelf row variants (contiguous), based on area scale\n    long double area = 0;\n    for(int i=0;i<N;i++) area += (long double)w[i] * (long double)h[i];\n    long long base = (long long) llround(sqrt((long double)max((long double)1.0, area)));\n    vector<long long> factors = {6,8,10,12,14,17,20,24,30,40};\n    for(long long f : factors){\n        long long M = max(1LL, base * f / 10);\n        plans.push_back(make_shelf_rows_width_limit(w,h,M));\n    }\n\n    // Prefix-columns brute force for m<=12\n    int Mmax = min(N, 12);\n    for(int m=2;m<=Mmax;m++){\n        Plan pl = make_prefix_columns_bruteforce(w,h,m);\n        if(pl.predScore < (1LL<<61)) plans.push_back(std::move(pl));\n    }\n\n    // Online columns with several biases (wide/narrow)\n    long long scale = max(10000LL, sigma * 5);\n    vector<long long> biases = {-4*scale, -2*scale, -scale, 0, scale, 2*scale, 4*scale};\n    for(long long b : biases){\n        plans.push_back(make_online_columns(w,h,b,0,nullptr));\n        plans.push_back(make_online_columns(w,h,b,1,nullptr));\n    }\n\n    // Additional randomized online plans to increase diversity\n    for(int it=0; it<800; it++){\n        long long b = (long long)((int64_t)(rng()% (uint64_t)(8*scale+1)) - (int64_t)(4*scale));\n        int headerMode = (rng()&1ULL) ? 0 : 1;\n        plans.push_back(make_online_columns(w,h,b,headerMode,&rng));\n    }\n\n    // Sort by predicted score and drop duplicates\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b){\n        if(a.predScore != b.predScore) return a.predScore < b.predScore;\n        return a.tag < b.tag;\n    });\n\n    vector<Plan> uniq;\n    uniq.reserve(plans.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(plans.size()*2);\n\n    for(auto &pl : plans){\n        if((int)pl.ops.size() != N) continue;\n        uint64_t hv = hash_plan_ops(pl.ops);\n        if(seen.insert(hv).second){\n            uniq.push_back(std::move(pl));\n            if((int)uniq.size() >= 500) break; // enough diversity\n        }\n    }\n\n    // Interactive loop: output T plans (best first; then cycle through remaining/random-like ones)\n    for(int t=0;t<T;t++){\n        const Plan* pl;\n        if(t < (int)uniq.size()) pl = &uniq[t];\n        else pl = &uniq[t % (int)uniq.size()];\n\n        cout << pl->ops.size() << '\\n';\n        for(const auto& op : pl->ops){\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        long long Wp, Hp;\n        if(!(cin >> Wp >> Hp)) break; // safety for non-interactive runs\n        // We do not adapt online in this simple solver.\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 1000;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    vector<bitset<MAXN>> adjbs(N);\n\n    vector<pair<int,int>> edges(M);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        edges[i] = {u, v};\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        adjbs[u].set(v);\n        adjbs[v].set(u);\n    }\n    // coordinates (unused)\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n    }\n\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto multisource_bfs_dist = [&](const vector<int>& sources) -> vector<int> {\n        const int INF = 1e9;\n        vector<int> dist(N, INF);\n        deque<int> q;\n        for (int s : sources) {\n            dist[s] = 0;\n            q.push_back(s);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            int nd = dist[v] + 1;\n            for (int to : adj[v]) {\n                if (dist[to] > nd) {\n                    dist[to] = nd;\n                    q.push_back(to);\n                }\n            }\n        }\n        return dist;\n    };\n\n    auto covered_within_H = [&](const vector<int>& roots) -> bool {\n        auto dist = multisource_bfs_dist(roots);\n        int mx = 0;\n        for (int d : dist) mx = max(mx, d);\n        return mx <= H;\n    };\n\n    // ---- 1) Choose roots so that every vertex is within distance <= H of some root.\n    int r0 = 0;\n    for (int i = 1; i < N; i++) if (A[i] < A[r0]) r0 = i;\n    vector<int> roots = {r0};\n\n    while (true) {\n        auto dist = multisource_bfs_dist(roots);\n        int mx = -1;\n        for (int i = 0; i < N; i++) mx = max(mx, dist[i]);\n        if (mx <= H) break;\n\n        // add a new root among farthest vertices; tie-break by small A\n        int best = -1;\n        for (int i = 0; i < N; i++) if (dist[i] == mx) {\n            if (best == -1 || A[i] < A[best]) best = i;\n        }\n        roots.push_back(best);\n    }\n\n    // Small root shifting: try replace each root by a low-A vertex within 2 hops, keeping coverage.\n    for (int idx = 0; idx < (int)roots.size(); idx++) {\n        int start = roots[idx];\n        vector<int> cand;\n        vector<int> dist(N, -1);\n        deque<int> q;\n        dist[start] = 0;\n        q.push_back(start);\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (dist[v] > 2) continue;\n            cand.push_back(v);\n            if (dist[v] == 2) continue;\n            for (int to : adj[v]) {\n                if (dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    q.push_back(to);\n                }\n            }\n        }\n        sort(cand.begin(), cand.end(), [&](int a, int b){\n            if (A[a] != A[b]) return A[a] < A[b];\n            return a < b;\n        });\n        for (int c : cand) {\n            if (c == roots[idx]) break; // already minimal in list until itself\n            int old = roots[idx];\n            roots[idx] = c;\n            if (covered_within_H(roots)) {\n                break;\n            }\n            roots[idx] = old;\n        }\n    }\n\n    // ---- 2) Build initial multi-source BFS forest (shortest-depth forest)\n    const int UNVIS = -2;\n    vector<int> parent(N, UNVIS);\n    vector<int> depth(N, (int)1e9);\n    deque<int> q;\n    for (int r : roots) {\n        parent[r] = -1;\n        depth[r] = 0;\n        q.push_back(r);\n    }\n    while (!q.empty()) {\n        int v = q.front(); q.pop_front();\n        if (depth[v] == H) continue;\n        for (int to : adj[v]) {\n            if (depth[to] > depth[v] + 1) {\n                depth[to] = depth[v] + 1;\n                parent[to] = v;\n                q.push_back(to);\n            }\n        }\n    }\n    // Safety: any unreachable becomes a root\n    for (int i = 0; i < N; i++) {\n        if (parent[i] == UNVIS) {\n            parent[i] = -1;\n            depth[i] = 0;\n        }\n    }\n\n    // ---- Maintain children lists with O(1) erase using positions.\n    vector<vector<int>> children(N);\n    vector<int> childPos(N, -1);\n\n    auto build_children = [&](){\n        for (int i = 0; i < N; i++) {\n            children[i].clear();\n            childPos[i] = -1;\n        }\n        for (int v = 0; v < N; v++) if (parent[v] != -1) {\n            int p = parent[v];\n            childPos[v] = (int)children[p].size();\n            children[p].push_back(v);\n        }\n    };\n\n    auto remove_child = [&](int p, int v){\n        int idx = childPos[v];\n        int last = children[p].back();\n        children[p][idx] = last;\n        childPos[last] = idx;\n        children[p].pop_back();\n        childPos[v] = -1;\n    };\n\n    auto add_child = [&](int p, int v){\n        childPos[v] = (int)children[p].size();\n        children[p].push_back(v);\n    };\n\n    build_children();\n\n    // Leaves set with O(1) add/remove\n    vector<int> leaves;\n    vector<int> leafPos(N, -1);\n    vector<char> inLeaves(N, 0);\n\n    auto make_leaf = [&](int v){\n        if (inLeaves[v]) return;\n        inLeaves[v] = 1;\n        leafPos[v] = (int)leaves.size();\n        leaves.push_back(v);\n    };\n    auto unmake_leaf = [&](int v){\n        if (!inLeaves[v]) return;\n        int idx = leafPos[v];\n        int last = leaves.back();\n        leaves[idx] = last;\n        leafPos[last] = idx;\n        leaves.pop_back();\n        inLeaves[v] = 0;\n        leafPos[v] = -1;\n    };\n    auto refresh_leaf = [&](int v){\n        if (children[v].empty()) make_leaf(v);\n        else unmake_leaf(v);\n    };\n\n    for (int v = 0; v < N; v++) refresh_leaf(v);\n\n    auto is_ancestor = [&](int anc, int node) -> bool {\n        int cur = node;\n        // depth is bounded by H, but be safe.\n        for (int step = 0; step <= H + 3 && cur != -1; step++) {\n            if (cur == anc) return true;\n            cur = parent[cur];\n        }\n        return false;\n    };\n\n    auto collect_subtree = [&](int v, vector<int>& nodes) {\n        nodes.clear();\n        vector<int> st;\n        st.push_back(v);\n        while (!st.empty()) {\n            int x = st.back();\n            st.pop_back();\n            nodes.push_back(x);\n            for (int ch : children[x]) st.push_back(ch);\n        }\n    };\n\n    // Reattach subtree rooted at v under u (u adjacent to v), increasing depths if delta>0.\n    vector<int> sub;\n    auto try_reattach = [&](int v, int u) -> bool {\n        if (u == v) return false;\n        if (!adjbs[v].test(u)) return false;\n        int ndv = depth[u] + 1;\n        if (ndv > H) return false;\n        int delta = ndv - depth[v];\n        if (delta <= 0) return false;\n        if (is_ancestor(v, u)) return false; // would create cycle\n\n        collect_subtree(v, sub);\n        int mx = 0;\n        for (int x : sub) mx = max(mx, depth[x]);\n        if (mx + delta > H) return false;\n\n        int oldp = parent[v];\n        if (oldp != -1) {\n            remove_child(oldp, v);\n            refresh_leaf(oldp);\n        }\n        parent[v] = u;\n        add_child(u, v);\n        refresh_leaf(u);\n\n        for (int x : sub) depth[x] += delta;\n        return true;\n    };\n\n    // Rotation around edge p->c (c is child of p):\n    // If gp exists, need edge gp-c. Depth effects:\n    // - subtree(c) depths -1\n    // - subtree(p) \\ subtree(c) depths +1\n    vector<int> subC, subP;\n    vector<int> mark(N, 0);\n    int markToken = 1;\n\n    auto try_rotate = [&](int c) -> bool {\n        int p = parent[c];\n        if (p == -1) return false;\n        int gp = parent[p];\n        if (gp != -1 && !adjbs[gp].test(c)) return false;\n\n        collect_subtree(c, subC);\n        collect_subtree(p, subP);\n\n        // Mark subC\n        markToken++;\n        for (int x : subC) mark[x] = markToken;\n\n        long long sumC = 0, sumOther = 0;\n        int mxOther = -1;\n        for (int x : subC) sumC += A[x];\n        for (int x : subP) {\n            if (mark[x] != markToken) {\n                sumOther += A[x];\n                mxOther = max(mxOther, depth[x]);\n            }\n        }\n        if (mxOther == -1) return false; // no \"other\" part, meaningless\n        if (mxOther + 1 > H) return false;\n\n        long long deltaScore = sumOther - sumC;\n        if (deltaScore <= 0) return false;\n\n        // Apply pointer changes:\n        // gp -> p becomes gp -> c, and p becomes child of c.\n        remove_child(p, c);\n        refresh_leaf(p);\n\n        if (gp != -1) {\n            remove_child(gp, p);\n            refresh_leaf(gp);\n            parent[c] = gp;\n            add_child(gp, c);\n            refresh_leaf(gp);\n        } else {\n            parent[c] = -1;\n        }\n\n        parent[p] = c;\n        add_child(c, p);\n        refresh_leaf(c);\n\n        // Update depths\n        for (int x : subC) depth[x] -= 1;\n        for (int x : subP) if (mark[x] != markToken) depth[x] += 1;\n\n        return true;\n    };\n\n    // ---- 3) Local improvement loop\n    Timer timer;\n    const double TL = 1.90;\n\n    auto best_deeper_neighbor = [&](int v) -> int {\n        int bestU = -1;\n        int bestDepth = -1;\n        for (int u : adj[v]) {\n            if (depth[u] >= H) continue;\n            if (depth[u] + 1 <= depth[v]) continue;\n            if (is_ancestor(v, u)) continue;\n            if (depth[u] > bestDepth) {\n                bestDepth = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    while (timer.elapsed_sec() < TL) {\n        uint64_t r = rng();\n        int mode = (int)(r % 100);\n\n        if (mode < 85) {\n            // Leaf reattach (fast)\n            if (leaves.empty()) continue;\n            int v = leaves[rng() % leaves.size()];\n            int u = best_deeper_neighbor(v);\n            if (u != -1) {\n                // leaf => subtree size 1 (collect_subtree is fine anyway)\n                try_reattach(v, u);\n            }\n        } else if (mode < 95) {\n            // Random subtree reattach\n            int v = (int)(rng() % N);\n            int u = best_deeper_neighbor(v);\n            if (u != -1) try_reattach(v, u);\n        } else {\n            // Rotation attempt\n            int c = (int)(rng() % N);\n            if (parent[c] != -1) try_rotate(c);\n        }\n    }\n\n    // ---- 4) Final legality repair (cycle/height)\n    auto repair = [&](){\n        bool changed = true;\n        int iter = 0;\n        while (changed && iter++ < 5) { // usually converges very fast\n            changed = false;\n\n            // break obvious cycles by making one node root if parent-chain loops\n            vector<int> state(N, 0); // 0 unvisited, 1 visiting, 2 done\n            for (int v = 0; v < N; v++) {\n                if (state[v] != 0) continue;\n                int cur = v;\n                while (cur != -1 && state[cur] == 0) {\n                    state[cur] = 1;\n                    cur = parent[cur];\n                }\n                if (cur != -1 && state[cur] == 1) {\n                    // found a cycle; break at v\n                    parent[v] = -1;\n                    changed = true;\n                }\n                // mark the path as done\n                cur = v;\n                while (cur != -1 && state[cur] == 1) {\n                    state[cur] = 2;\n                    cur = parent[cur];\n                }\n            }\n\n            build_children();\n            for (int v = 0; v < N; v++) refresh_leaf(v);\n\n            // recompute depths from roots\n            fill(depth.begin(), depth.end(), -1);\n            deque<int> qq;\n            for (int v = 0; v < N; v++) {\n                if (parent[v] == -1) {\n                    depth[v] = 0;\n                    qq.push_back(v);\n                }\n            }\n            while (!qq.empty()) {\n                int v = qq.front(); qq.pop_front();\n                for (int ch : children[v]) {\n                    depth[ch] = depth[v] + 1;\n                    qq.push_back(ch);\n                }\n            }\n            // unreachable => make root\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == -1) {\n                    parent[v] = -1;\n                    changed = true;\n                }\n            }\n\n            if (changed) continue;\n\n            // enforce height <= H by cutting nodes that exceed H\n            // (cutting reduces depths, never violates)\n            build_children();\n            fill(depth.begin(), depth.end(), -1);\n            qq.clear();\n            for (int v = 0; v < N; v++) if (parent[v] == -1) {\n                depth[v] = 0;\n                qq.push_back(v);\n            }\n            while (!qq.empty()) {\n                int v = qq.front(); qq.pop_front();\n                for (int ch : children[v]) {\n                    depth[ch] = depth[v] + 1;\n                    qq.push_back(ch);\n                }\n            }\n            for (int v = 0; v < N; v++) {\n                if (depth[v] > H) {\n                    parent[v] = -1;\n                    changed = true;\n                }\n            }\n        }\n\n        // final: ensure parent edge exists (should already)\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) continue;\n            if (!adjbs[v].test(parent[v])) parent[v] = -1;\n        }\n    };\n\n    repair();\n\n    // Output\n    for (int i = 0; i < N; i++) {\n        cout << parent[i] << (i + 1 == N ? '\\n' : ' ');\n    }\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\n\nstruct Option {\n    bool valid = false;\n    int type = -1; // 0:U col, 1:D col, 2:L row, 3:R row\n    int idx = -1;  // row or col index\n    int depth = 0; // required K\n};\n\nstruct Oni {\n    int r, c;\n    array<Option,4> opt; // 0:U 1:D 2:L 3:R\n    vector<int> feasibleDirs;\n    bool fixed = false;\n};\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto t = steady_clock::now() - st;\n    return duration<double>(t).count();\n}\n\nint computeCost(const vector<Oni>& onis, const vector<int>& dir,\n                array<int,N>& U, array<int,N>& D, array<int,N>& L, array<int,N>& R) {\n    U.fill(0); D.fill(0); L.fill(0); R.fill(0);\n    for (int k = 0; k < (int)onis.size(); k++) {\n        const auto &o = onis[k];\n        const Option &op = o.opt[dir[k]];\n        // assumed valid\n        if (op.type == 0) U[op.idx] = max(U[op.idx], op.depth);\n        else if (op.type == 1) D[op.idx] = max(D[op.idx], op.depth);\n        else if (op.type == 2) L[op.idx] = max(L[op.idx], op.depth);\n        else if (op.type == 3) R[op.idx] = max(R[op.idx], op.depth);\n    }\n    int sum = 0;\n    for (int i = 0; i < N; i++) sum += U[i] + D[i] + L[i] + R[i];\n    return sum;\n}\n\nint computeCostOnly(const vector<Oni>& onis, const vector<int>& dir) {\n    array<int,N> U,D,L,R;\n    return computeCost(onis, dir, U, D, L, R);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<string> C(n);\n    for (int i = 0; i < n; i++) cin >> C[i];\n\n    // Limits based on Fukunokami positions (fixed-safe depths)\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    left_limit.fill(N);\n    right_limit.fill(N);\n    up_limit.fill(N);\n    down_limit.fill(N);\n\n    // Row limits\n    for (int i = 0; i < N; i++) {\n        int first = N, last = -1;\n        for (int j = 0; j < N; j++) if (C[i][j] == 'o') {\n            first = min(first, j);\n            last = max(last, j);\n        }\n        left_limit[i] = first; // K <= first\n        if (last == -1) right_limit[i] = N;\n        else right_limit[i] = (N - 1 - last); // K <= dist from last o to right edge\n    }\n    // Col limits\n    for (int j = 0; j < N; j++) {\n        int first = N, last = -1;\n        for (int i = 0; i < N; i++) if (C[i][j] == 'o') {\n            first = min(first, i);\n            last = max(last, i);\n        }\n        up_limit[j] = first; // K <= first\n        if (last == -1) down_limit[j] = N;\n        else down_limit[j] = (N - 1 - last);\n    }\n\n    // Gather Oni\n    vector<Oni> onis;\n    onis.reserve(2*N);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (C[i][j] != 'x') continue;\n        Oni o;\n        o.r = i; o.c = j;\n\n        // U\n        {\n            int K = i + 1;\n            if (K <= up_limit[j]) {\n                o.opt[0] = Option{true, 0, j, K};\n                o.feasibleDirs.push_back(0);\n            }\n        }\n        // D\n        {\n            int K = N - i;\n            if (K <= down_limit[j]) {\n                o.opt[1] = Option{true, 1, j, K};\n                o.feasibleDirs.push_back(1);\n            }\n        }\n        // L\n        {\n            int K = j + 1;\n            if (K <= left_limit[i]) {\n                o.opt[2] = Option{true, 2, i, K};\n                o.feasibleDirs.push_back(2);\n            }\n        }\n        // R\n        {\n            int K = N - j;\n            if (K <= right_limit[i]) {\n                o.opt[3] = Option{true, 3, i, K};\n                o.feasibleDirs.push_back(3);\n            }\n        }\n\n        // Guaranteed at least one feasible direction by problem statement\n        if (o.feasibleDirs.empty()) {\n            // Fallback (should not happen)\n            // But to avoid crashing: assign Up with K=1 (unsafe), still.\n            o.feasibleDirs.push_back(0);\n            o.opt[0] = Option{true,0,j,1};\n        }\n        if (o.feasibleDirs.size() == 1) o.fixed = true;\n\n        onis.push_back(o);\n    }\n\n    int M = (int)onis.size();\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937_64 rng(seed);\n\n    auto randInt = [&](int lo, int hi)->int{ // inclusive\n        std::uniform_int_distribution<int> dist(lo, hi);\n        return dist(rng);\n    };\n    auto randDouble = [&]()->double{\n        std::uniform_real_distribution<double> dist(0.0, 1.0);\n        return dist(rng);\n    };\n\n    // Initial assignment: minimal required depth (greedy)\n    vector<int> curDir(M, 0);\n    for (int k = 0; k < M; k++) {\n        int bestd = -1;\n        int bestK = INT_MAX;\n        // slight randomness among ties\n        vector<int> ties;\n        for (int d : onis[k].feasibleDirs) {\n            int dep = onis[k].opt[d].depth;\n            if (dep < bestK) {\n                bestK = dep;\n                ties.clear();\n                ties.push_back(d);\n            } else if (dep == bestK) {\n                ties.push_back(d);\n            }\n        }\n        bestd = ties[randInt(0, (int)ties.size()-1)];\n        curDir[k] = bestd;\n    }\n\n    int curCost = computeCostOnly(onis, curDir);\n    vector<int> bestDir = curDir;\n    int bestCost = curCost;\n\n    // Simulated annealing\n    double start = now_sec();\n    double TL = 1.90; // aim under 2s\n    const double T0 = 30.0;\n    const double T1 = 0.5;\n\n    while (true) {\n        double t = now_sec() - start;\n        if (t >= TL) break;\n        double p = t / TL;\n        double temp = T0 * (1.0 - p) + T1 * p;\n\n        int k = randInt(0, M-1);\n        if (onis[k].fixed) continue;\n\n        const auto &fds = onis[k].feasibleDirs;\n        if ((int)fds.size() <= 1) continue;\n\n        int old = curDir[k];\n        int nd = old;\n        // pick different feasible direction\n        for (int tries = 0; tries < 10; tries++) {\n            nd = fds[randInt(0, (int)fds.size()-1)];\n            if (nd != old) break;\n        }\n        if (nd == old) continue;\n\n        curDir[k] = nd;\n        int newCost = computeCostOnly(onis, curDir);\n        int delta = newCost - curCost;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(- (double)delta / temp);\n            if (randDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curCost = newCost;\n            if (curCost < bestCost) {\n                bestCost = curCost;\n                bestDir = curDir;\n            }\n        } else {\n            curDir[k] = old;\n        }\n    }\n\n    // Final coordinate descent (greedy local improvement)\n    curDir = bestDir;\n    curCost = bestCost;\n    bool improved = true;\n    for (int it = 0; it < 30 && improved; it++) {\n        improved = false;\n        for (int k = 0; k < M; k++) {\n            if (onis[k].fixed) continue;\n            int old = curDir[k];\n            int bestd = old;\n            int bestLocalCost = curCost;\n            for (int nd : onis[k].feasibleDirs) {\n                if (nd == old) continue;\n                curDir[k] = nd;\n                int cst = computeCostOnly(onis, curDir);\n                if (cst < bestLocalCost) {\n                    bestLocalCost = cst;\n                    bestd = nd;\n                }\n            }\n            curDir[k] = old;\n            if (bestd != old) {\n                curDir[k] = bestd;\n                curCost = bestLocalCost;\n                improved = true;\n            }\n        }\n    }\n    bestDir = curDir;\n    bestCost = curCost;\n\n    // Build depths from best assignment\n    array<int,N> U,D,L,R;\n    computeCost(onis, bestDir, U, D, L, R);\n\n    // Output operations\n    vector<pair<char,int>> ans;\n    ans.reserve(2 * bestCost);\n\n    auto addRepeat = [&](char ch, int idx, int k) {\n        for (int t = 0; t < k; t++) ans.push_back({ch, idx});\n    };\n\n    // Columns: top deletions then bottom deletions\n    for (int j = 0; j < N; j++) {\n        int k = U[j];\n        if (k > 0) {\n            addRepeat('U', j, k);\n            addRepeat('D', j, k);\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int k = D[j];\n        if (k > 0) {\n            addRepeat('D', j, k);\n            addRepeat('U', j, k);\n        }\n    }\n\n    // Rows: left deletions then right deletions\n    for (int i = 0; i < N; i++) {\n        int k = L[i];\n        if (k > 0) {\n            addRepeat('L', i, k);\n            addRepeat('R', i, k);\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        int k = R[i];\n        if (k > 0) {\n            addRepeat('R', i, k);\n            addRepeat('L', i, k);\n        }\n    }\n\n    // Safety: must be <= 4N^2\n    // (Should always hold because each Oni contributes depth<=20 and there are 40 Oni.)\n    if ((int)ans.size() > 4 * N * N) {\n        // Fallback: output nothing (would score poorly but avoid WA by too many ops).\n        // However, this should not happen.\n        ans.clear();\n    }\n\n    for (auto [ch, idx] : ans) {\n        cout << ch << \" \" << idx << \"\\n\";\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N_FIXED = 100;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int mod) { return (int)(nextU64() % (uint64_t)mod); }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Plan {\n    array<int, N_FIXED> a;\n    array<int, N_FIXED> b;\n};\n\nstatic inline int iabs_int(int x) { return x < 0 ? -x : x; }\n\nint simulate_plan(const Plan& p, int L, const array<int, N_FIXED>& T, array<int, N_FIXED>& cnt) {\n    cnt.fill(0);\n    int cur = 0;\n    cnt[0] = 1;\n    for (int step = 1; step < L; ++step) {\n        int x = cur;\n        cur = (cnt[x] & 1) ? p.a[x] : p.b[x];\n        ++cnt[cur];\n    }\n    int E = 0;\n    for (int i = 0; i < N_FIXED; ++i) E += iabs_int(cnt[i] - T[i]);\n    return E;\n}\n\nint sample_weighted(const array<long long, N_FIXED>& w, long long sumW, RNG& rng) {\n    if (sumW <= 0) return rng.nextInt(N_FIXED);\n    long long r = (long long)(rng.nextU64() % (uint64_t)sumW);\n    long long acc = 0;\n    for (int i = 0; i < N_FIXED; ++i) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return N_FIXED - 1;\n}\n\n// Ensure every node with T>0 is reachable from 0 (just a safety net against totally broken initial graphs).\nvoid ensure_reachable_from0(Plan& p, const array<int, N_FIXED>& T) {\n    auto reachable = [&](vector<char>& vis) {\n        vis.assign(N_FIXED, 0);\n        queue<int> q;\n        vis[0] = 1;\n        q.push(0);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int to1 = p.a[v], to2 = p.b[v];\n            if (!vis[to1]) { vis[to1] = 1; q.push(to1); }\n            if (!vis[to2]) { vis[to2] = 1; q.push(to2); }\n        }\n    };\n\n    vector<char> vis;\n    reachable(vis);\n\n    // Try to connect unreachable positive-target nodes by redirecting an edge from a reachable small-T node.\n    for (int it = 0; it < 300; ++it) {\n        int u = -1;\n        for (int i = 0; i < N_FIXED; ++i) {\n            if (T[i] > 0 && !vis[i]) { u = i; break; }\n        }\n        if (u == -1) break;\n\n        int v = -1;\n        int bestT = INT_MAX;\n        for (int i = 0; i < N_FIXED; ++i) if (vis[i]) {\n            if (T[i] < bestT) { bestT = T[i]; v = i; }\n        }\n        if (v == -1) break;\n\n        // Redirect the less \"important\" edge (heuristic: b-edge).\n        p.b[v] = u;\n        reachable(vis);\n    }\n}\n\nPlan gen_random_plan(const array<int, N_FIXED>& T, RNG& rng) {\n    Plan p;\n    long long sumT = 0;\n    for (int i = 0; i < N_FIXED; ++i) sumT += T[i];\n    array<long long, N_FIXED> w;\n    for (int i = 0; i < N_FIXED; ++i) w[i] = T[i];\n\n    for (int i = 0; i < N_FIXED; ++i) {\n        p.a[i] = sample_weighted(w, sumT, rng);\n        p.b[i] = sample_weighted(w, sumT, rng);\n    }\n    return p;\n}\n\n// Weighted balancing initializer: assign 2 outgoing \"stubs\" per node with weight T[i]\n// to approximately meet incoming weighted demand 2*T[j].\nPlan gen_balanced_plan(const array<int, N_FIXED>& T, RNG& rng) {\n    struct Stub { int i, k; int w; }; // edge is (i,k) where k=0=>a,1=>b\n    vector<Stub> stubs;\n    stubs.reserve(2 * N_FIXED);\n    for (int i = 0; i < N_FIXED; ++i) {\n        stubs.push_back({i, 0, T[i]});\n        stubs.push_back({i, 1, T[i]});\n    }\n    sort(stubs.begin(), stubs.end(), [](const Stub& x, const Stub& y){ return x.w < y.w; });\n\n    vector<int> pos;\n    pos.reserve(N_FIXED);\n    for (int j = 0; j < N_FIXED; ++j) if (T[j] > 0) pos.push_back(j);\n    sort(pos.begin(), pos.end(), [&](int a, int b){ return T[a] < T[b]; });\n\n    vector<long long> rem(N_FIXED);\n    for (int j = 0; j < N_FIXED; ++j) rem[j] = 2LL * T[j];\n\n    Plan p;\n    p.a.fill(0); p.b.fill(0);\n\n    int s = 0;\n    // Coverage: give each T>0 node at least one incoming stub (using small-weight stubs first).\n    for (int j : pos) {\n        if (s >= (int)stubs.size()) break;\n        auto st = stubs[s++];\n        if (st.k == 0) p.a[st.i] = j;\n        else p.b[st.i] = j;\n        rem[j] -= st.w;\n    }\n\n    // Remaining stubs: greedy by maximum remaining demand.\n    using PII = pair<long long,int>;\n    priority_queue<PII> pq;\n    for (int j = 0; j < N_FIXED; ++j) pq.push({rem[j], j});\n\n    for (; s < (int)stubs.size(); ++s) {\n        auto st = stubs[s];\n\n        // pick among top-3 a bit randomly to diversify\n        array<PII,3> top;\n        int k = 0;\n        for (; k < 3 && !pq.empty(); ++k) { top[k] = pq.top(); pq.pop(); }\n        int pick = 0;\n        if (k >= 2 && rng.nextInt(4) == 0) pick = 1;\n        if (k >= 3 && rng.nextInt(10) == 0) pick = 2;\n        int j = top[pick].second;\n\n        // push back the non-picked\n        for (int t = 0; t < k; ++t) if (t != pick) pq.push(top[t]);\n\n        if (st.k == 0) p.a[st.i] = j;\n        else p.b[st.i] = j;\n\n        long long newrem = top[pick].first - st.w;\n        pq.push({newrem, j});\n    }\n\n    // For T==0 nodes, try to avoid attracting flow: make them point to a high-demand hub.\n    int hub = 0;\n    for (int i = 1; i < N_FIXED; ++i) if (T[i] > T[hub]) hub = i;\n    for (int i = 0; i < N_FIXED; ++i) {\n        if (T[i] == 0) { p.a[i] = hub; p.b[i] = hub; }\n    }\n\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, N_FIXED> T{};\n    for (int i = 0; i < N_FIXED; ++i) cin >> T[i];\n\n    // RNG seed: fixed + small dependence on input\n    uint64_t seed = 123456789ULL;\n    for (int i = 0; i < N_FIXED; ++i) seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    RNG rng(seed);\n\n    auto time_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.90;\n\n    // Build several initial plans and take the best.\n    Plan curP, bestP;\n    array<int, N_FIXED> curCnt, bestCnt, tmpCnt;\n    int curE = INT_MAX, bestE = INT_MAX;\n\n    auto try_init = [&](Plan p) {\n        ensure_reachable_from0(p, T);\n        int E = simulate_plan(p, L, T, tmpCnt);\n        if (E < bestE) {\n            bestE = E;\n            bestP = p;\n            bestCnt = tmpCnt;\n        }\n    };\n\n    try_init(gen_balanced_plan(T, rng));\n    for (int k = 0; k < 5; ++k) try_init(gen_random_plan(T, rng));\n\n    curP = bestP;\n    curE = bestE;\n    curCnt = bestCnt;\n\n    // SA parameters\n    const double T0 = 8000.0;\n    const double T1 = 50.0;\n\n    // SA loop\n    while (elapsedSec() < TIME_LIMIT) {\n        double t = elapsedSec() / TIME_LIMIT;\n        double temp = T0 * pow(T1 / T0, t);\n\n        int moveType = rng.nextInt(100);\n        int x1=-1, e1=0, old1=-1;\n        int x2=-1, e2=0, old2=-1;\n        int olda=-1, oldb=-1;\n\n        auto choose_x = [&]() -> int {\n            // half: proportional-to-visit-count sampling, half: uniform\n            if (rng.nextInt(2) == 0) return rng.nextInt(N_FIXED);\n            int maxC = 1;\n            for (int i = 0; i < N_FIXED; ++i) maxC = max(maxC, curCnt[i]);\n            while (true) {\n                int i = rng.nextInt(N_FIXED);\n                if (rng.nextInt(maxC) < curCnt[i]) return i;\n            }\n        };\n\n        auto choose_dest = [&]() -> int {\n            // Prefer under-visited nodes.\n            array<long long, N_FIXED> w;\n            long long sumW = 0;\n            for (int i = 0; i < N_FIXED; ++i) {\n                int d = T[i] - curCnt[i];\n                long long wi = (d > 0 ? (long long)d : 0LL);\n                w[i] = wi;\n                sumW += wi;\n            }\n            if (sumW == 0) {\n                // fallback to target distribution\n                sumW = 0;\n                for (int i = 0; i < N_FIXED; ++i) { w[i] = T[i]; sumW += w[i]; }\n                if (sumW == 0) { // should not happen (sum T = L)\n                    for (int i = 0; i < N_FIXED; ++i) w[i] = 1;\n                    sumW = N_FIXED;\n                }\n            }\n            return sample_weighted(w, sumW, rng);\n        };\n\n        // Apply a move\n        if (moveType < 70) {\n            // change one edge\n            x1 = choose_x();\n            e1 = rng.nextInt(2);\n            old1 = (e1 == 0 ? curP.a[x1] : curP.b[x1]);\n\n            int y;\n            if (rng.nextInt(100) < 75) y = choose_dest();\n            else y = rng.nextInt(N_FIXED);\n            if (y == old1) continue;\n\n            if (e1 == 0) curP.a[x1] = y;\n            else curP.b[x1] = y;\n        } else if (moveType < 90) {\n            // swap two edges\n            x1 = choose_x(); e1 = rng.nextInt(2);\n            x2 = choose_x(); e2 = rng.nextInt(2);\n            old1 = (e1 == 0 ? curP.a[x1] : curP.b[x1]);\n            old2 = (e2 == 0 ? curP.a[x2] : curP.b[x2]);\n            if (old1 == old2) continue;\n\n            if (e1 == 0) curP.a[x1] = old2; else curP.b[x1] = old2;\n            if (e2 == 0) curP.a[x2] = old1; else curP.b[x2] = old1;\n        } else {\n            // reset both edges of one node\n            x1 = choose_x();\n            olda = curP.a[x1];\n            oldb = curP.b[x1];\n\n            int y1 = (rng.nextInt(100) < 75) ? choose_dest() : rng.nextInt(N_FIXED);\n            int y2 = (rng.nextInt(100) < 75) ? choose_dest() : rng.nextInt(N_FIXED);\n            if (y1 == olda && y2 == oldb) continue;\n\n            curP.a[x1] = y1;\n            curP.b[x1] = y2;\n        }\n\n        int newE = simulate_plan(curP, L, T, tmpCnt);\n        int delta = newE - curE;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(-(double)delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curE = newE;\n            curCnt = tmpCnt;\n            if (curE < bestE) {\n                bestE = curE;\n                bestP = curP;\n                bestCnt = curCnt;\n            }\n        } else {\n            // revert\n            if (moveType < 70) {\n                if (e1 == 0) curP.a[x1] = old1;\n                else curP.b[x1] = old1;\n            } else if (moveType < 90) {\n                if (e1 == 0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2 == 0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n        }\n    }\n\n    // Output best plan found\n    for (int i = 0; i < N_FIXED; ++i) {\n        cout << bestP.a[i] << ' ' << bestP.b[i] << \"\\n\";\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\n\nusing namespace std;\n\nstruct City {\n    int lx, rx, ly, ry;\n    int cx, cy;          // estimated center\n    uint32_t morton;     // Z-order key\n};\n\nstatic inline uint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nstatic inline uint32_t morton2D(uint32_t x, uint32_t y) {\n    return part1by1(x) | (part1by1(y) << 1);\n}\n\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<City> cities;\n\n    // estimated distances (floor(sqrt(dx^2+dy^2))) based on centers\n    vector<uint16_t> distMat; // N*N\n\n    int q_used = 0;\n\n    vector<vector<int>> groups; // group -> city list\n    vector<vector<pair<int,int>>> queryEdges; // group -> edges obtained from queries\n    vector<char> fullQueried; // group queried entirely (so we can just use its MST)\n\n    uint16_t dist_est(int a, int b) const {\n        return distMat[a * N + b];\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int v : subset) cout << \" \" << v;\n        cout << \"\\n\" << flush;\n\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, l - 1));\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            cin >> a >> b;\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        q_used++;\n        return edges;\n    }\n\n    vector<pair<int,int>> prim_tree_edges(const vector<int>& nodes) {\n        int s = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (s <= 1) return edges;\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        vector<uint16_t> minc(s, INF);\n        vector<int> parent(s, -1);\n        vector<char> used(s, false);\n\n        minc[0] = 0;\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) {\n                if (!used[i] && (v == -1 || minc[i] < minc[v])) v = i;\n            }\n            used[v] = true;\n            if (parent[v] != -1) {\n                int a = nodes[v], b = nodes[parent[v]];\n                if (a > b) swap(a, b);\n                edges.emplace_back(a, b);\n            }\n            for (int u = 0; u < s; u++) if (!used[u]) {\n                uint16_t d = dist_est(nodes[v], nodes[u]);\n                if (d < minc[u]) {\n                    minc[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n        return edges;\n    }\n\n    vector<pair<int,int>> build_final_tree(int k) {\n        const vector<int>& nodes = groups[k];\n        int s = (int)nodes.size();\n        vector<pair<int,int>> result;\n        if (s <= 1) return result;\n\n        // If fully queried, we should have exactly s-1 edges already.\n        if (fullQueried[k]) {\n            result = queryEdges[k];\n            // Safety: if something went wrong, fall back.\n            if ((int)result.size() == s - 1) return result;\n        }\n\n        // Fallback edges from estimated Prim tree\n        vector<pair<int,int>> fallback = prim_tree_edges(nodes);\n\n        // Combine: process query edges first (shorter estimated first), then fallback (also sorted)\n        vector<pair<int,int>> qE = queryEdges[k];\n\n        auto edge_weight = [&](const pair<int,int>& e) -> uint16_t {\n            return dist_est(e.first, e.second);\n        };\n\n        // Deduplicate edges inside each list\n        auto dedup = [&](vector<pair<int,int>>& es) {\n            for (auto &p : es) if (p.first > p.second) swap(p.first, p.second);\n            sort(es.begin(), es.end());\n            es.erase(unique(es.begin(), es.end()), es.end());\n        };\n        dedup(qE);\n        dedup(fallback);\n\n        sort(qE.begin(), qE.end(), [&](auto &a, auto &b) {\n            uint16_t da = edge_weight(a), db = edge_weight(b);\n            if (da != db) return da < db;\n            return a < b;\n        });\n        sort(fallback.begin(), fallback.end(), [&](auto &a, auto &b) {\n            uint16_t da = edge_weight(a), db = edge_weight(b);\n            if (da != db) return da < db;\n            return a < b;\n        });\n\n        // Map global city id -> local index 0..s-1\n        static vector<int> pos;\n        pos.assign(N, -1);\n        for (int i = 0; i < s; i++) pos[nodes[i]] = i;\n\n        atcoder::dsu dsu(s);\n        auto try_add = [&](int a, int b) {\n            int pa = pos[a], pb = pos[b];\n            if (pa < 0 || pb < 0) return false;\n            if (dsu.same(pa, pb)) return false;\n            dsu.merge(pa, pb);\n            if (a > b) swap(a, b);\n            result.emplace_back(a, b);\n            return true;\n        };\n\n        for (auto &e : qE) try_add(e.first, e.second);\n        for (auto &e : fallback) try_add(e.first, e.second);\n\n        // Extremely unlikely, but ensure we end with exactly s-1 edges\n        if ((int)result.size() != s - 1) {\n            // brute-force connect remaining components using estimated nearest edges\n            vector<int> compRep(s, -1);\n            for (int i = 0; i < s; i++) {\n                int r = dsu.leader(i);\n                if (compRep[r] == -1) compRep[r] = i;\n            }\n            vector<int> reps;\n            for (int i = 0; i < s; i++) if (compRep[i] != -1) reps.push_back(compRep[i]);\n\n            // connect reps in a chain by nearest neighbor heuristic\n            while ((int)reps.size() > 1 && (int)result.size() < s - 1) {\n                int aidx = reps.back(); reps.pop_back();\n                int bestj = -1;\n                uint16_t bestd = numeric_limits<uint16_t>::max();\n                for (int j = 0; j < (int)reps.size(); j++) {\n                    uint16_t d = dist_est(nodes[aidx], nodes[reps[j]]);\n                    if (d < bestd) {\n                        bestd = d;\n                        bestj = j;\n                    }\n                }\n                if (bestj == -1) break;\n                try_add(nodes[aidx], nodes[reps[bestj]]);\n                // merge leaders list roughly\n                reps[bestj] = dsu.leader(reps[bestj]);\n                // rebuild reps\n                vector<int> newReps;\n                vector<char> seen(s, false);\n                for (int i = 0; i < s; i++) {\n                    int r = dsu.leader(i);\n                    if (!seen[r]) { seen[r] = true; newReps.push_back(r); }\n                }\n                reps.swap(newReps);\n            }\n        }\n\n        // If still not exact, truncate (should not happen), but keep legality.\n        if ((int)result.size() > s - 1) result.resize(s - 1);\n        return result;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        cities.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto &c = cities[i];\n            cin >> c.lx >> c.rx >> c.ly >> c.ry;\n            c.cx = (c.lx + c.rx) / 2;\n            c.cy = (c.ly + c.ry) / 2;\n\n            // coordinates are within [0,10000], fit in 14 bits.\n            uint32_t x = (uint32_t)min(16383, max(0, c.cx));\n            uint32_t y = (uint32_t)min(16383, max(0, c.cy));\n            c.morton = morton2D(x, y);\n        }\n\n        // Precompute estimated distances\n        distMat.assign((size_t)N * N, 0);\n        for (int i = 0; i < N; i++) {\n            distMat[i * N + i] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = cities[i].cx - cities[j].cx;\n                long long dy = cities[i].cy - cities[j].cy;\n                long long sq = dx * dx + dy * dy;\n                int d = (int)floor(sqrt((double)sq));\n                if (d < 0) d = 0;\n                if (d > 65535) d = 65535;\n                distMat[i * N + j] = (uint16_t)d;\n                distMat[j * N + i] = (uint16_t)d;\n            }\n        }\n\n        // Morton order\n        vector<int> mortOrder(N);\n        iota(mortOrder.begin(), mortOrder.end(), 0);\n        sort(mortOrder.begin(), mortOrder.end(), [&](int a, int b) {\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n\n        // Build groups by growing clusters (Prim-like) from earliest unused Morton city\n        vector<char> used(N, false);\n        groups.assign(M, {});\n        queryEdges.assign(M, {});\n        fullQueried.assign(M, false);\n\n        vector<int> groupOrder(M);\n        iota(groupOrder.begin(), groupOrder.end(), 0);\n        sort(groupOrder.begin(), groupOrder.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        int mortPtr = 0;\n        auto next_seed = [&]() -> int {\n            while (mortPtr < N && used[mortOrder[mortPtr]]) mortPtr++;\n            if (mortPtr >= N) {\n                // Should never happen; fallback scan\n                for (int i = 0; i < N; i++) if (!used[i]) return i;\n                return -1;\n            }\n            return mortOrder[mortPtr];\n        };\n\n        vector<uint16_t> best(N);\n        for (int idx : groupOrder) {\n            int s = G[idx];\n            vector<int> grp;\n            grp.reserve(s);\n\n            int seed = next_seed();\n            if (seed == -1) break;\n            used[seed] = true;\n            grp.push_back(seed);\n\n            // initialize best distances to group\n            for (int v = 0; v < N; v++) {\n                if (!used[v]) best[v] = dist_est(seed, v);\n            }\n\n            for (int t = 1; t < s; t++) {\n                int pick = -1;\n                uint16_t bd = numeric_limits<uint16_t>::max();\n                for (int v = 0; v < N; v++) {\n                    if (used[v]) continue;\n                    uint16_t d = best[v];\n                    if (pick == -1 || d < bd) {\n                        bd = d;\n                        pick = v;\n                    }\n                }\n                if (pick == -1) break; // should not happen\n                used[pick] = true;\n                grp.push_back(pick);\n\n                // update best distances\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = dist_est(pick, v);\n                    if (d < best[v]) best[v] = d;\n                }\n            }\n            groups[idx] = move(grp);\n        }\n\n        // --- Queries ---\n        // 1) Query all groups with 3 <= size <= L once (exact MST)\n        for (int k = 0; k < M; k++) {\n            int s = (int)groups[k].size();\n            if (s >= 3 && s <= L && q_used < Q) {\n                queryEdges[k] = do_query(groups[k]);\n                fullQueried[k] = true;\n            }\n        }\n\n        // 2) Use remaining queries for large groups: block MSTs + representative windows\n        for (int k : groupOrder) {\n            if (q_used >= Q) break;\n            int s = (int)groups[k].size();\n            if (s <= L) continue; // already handled or not queryable\n\n            // Sort group nodes by Morton for locality\n            vector<int> nodes = groups[k];\n            sort(nodes.begin(), nodes.end(), [&](int a, int b) {\n                if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n                if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n                return cities[a].cy < cities[b].cy;\n            });\n\n            // Blocks of size L\n            vector<vector<int>> blocks;\n            for (int i = 0; i < s; i += L) {\n                int j = min(s, i + L);\n                vector<int> blk(nodes.begin() + i, nodes.begin() + j);\n                blocks.push_back(move(blk));\n            }\n\n            // Query each block MST if size>=3\n            for (auto &blk : blocks) {\n                if (q_used >= Q) break;\n                if ((int)blk.size() >= 3) {\n                    auto e = do_query(blk);\n                    queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                }\n            }\n            if (q_used >= Q) break;\n\n            // Representatives\n            vector<int> reps;\n            reps.reserve(blocks.size());\n            for (auto &blk : blocks) reps.push_back(blk[0]);\n\n            // Query overlapping windows of reps to connect blocks\n            if ((int)reps.size() >= 3 && q_used < Q) {\n                int step = max(1, L - 1);\n                for (int start = 0; start < (int)reps.size() - 1 && q_used < Q; start += step) {\n                    int end = min((int)reps.size(), start + L);\n                    vector<int> sub(reps.begin() + start, reps.begin() + end);\n                    if ((int)sub.size() < 3) break;\n                    auto e = do_query(sub);\n                    queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                    if (end == (int)reps.size()) break;\n                }\n            }\n        }\n\n        // --- Output final answer ---\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            // print cities\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            // build and print edges\n            auto edges = build_final_tree(k);\n            // Ensure exactly G[k]-1 lines (for legality)\n            int need = (int)groups[k].size() - 1;\n            if ((int)edges.size() != need) {\n                // fallback to pure estimated Prim (always size-1 when size>=1)\n                edges = prim_tree_edges(groups[k]);\n            }\n            for (auto &e : edges) {\n                cout << e.first << \" \" << e.second << \"\\n\";\n            }\n        }\n        cout << flush;\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char a, d;\n};\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dirc[4] = {'U', 'D', 'L', 'R'};\nstatic const char actc[3] = {'M', 'S', 'A'};\n\nstruct Solver {\n    int N, M;\n    vector<pair<int,int>> P; // P[0]=start, P[1..M-1]=targets\n    bool isTarget[20][20]{};\n    bool blockg[20][20]{};\n    int totalBlocks = 0;\n\n    const int KMAX = 12;\n    const int INF = 1e9;\n    const int MAX_BLOCKS = 80;\n\n    vector<Action> answer;\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int posId(int x, int y) const { return x * N + y; }\n    pair<int,int> idPos(int id) const { return {id / N, id % N}; }\n\n    // Slide stop with fixed global blocks.\n    int slideStopFixed(int x, int y, int dir) const {\n        int nx = x, ny = y;\n        while (true) {\n            int tx = nx + di[dir], ty = ny + dj[dir];\n            if (!inside(tx, ty)) break;\n            if (blockg[tx][ty]) break;\n            nx = tx; ny = ty;\n        }\n        return posId(nx, ny);\n    }\n\n    // BFS on positions only, allowed actions: Move + Slide, with fixed global blocks.\n    vector<Action> shortestFixed(pair<int,int> s, pair<int,int> g) const {\n        int S = posId(s.first, s.second);\n        int G = posId(g.first, g.second);\n\n        vector<int> dist(N*N, -1), prev(N*N, -1);\n        vector<uint8_t> prevOp(N*N, 255);\n\n        vector<int> q;\n        q.reserve(N*N);\n        dist[S] = 0;\n        q.push_back(S);\n        size_t head = 0;\n\n        while (head < q.size()) {\n            int v = q[head++];\n            if (v == G) break;\n            auto [x, y] = idPos(v);\n\n            for (int d = 0; d < 4; d++) {\n                // Move\n                int mx = x + di[d], my = y + dj[d];\n                if (inside(mx, my) && !blockg[mx][my]) {\n                    int to = posId(mx, my);\n                    if (dist[to] == -1) {\n                        dist[to] = dist[v] + 1;\n                        prev[to] = v;\n                        prevOp[to] = (0 * 4 + d); // M\n                        q.push_back(to);\n                    }\n                }\n                // Slide\n                int to = slideStopFixed(x, y, d);\n                if (to != v && dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    prev[to] = v;\n                    prevOp[to] = (1 * 4 + d); // S\n                    q.push_back(to);\n                }\n            }\n        }\n\n        if (dist[G] == -1) return {}; // should not happen in normal runs\n\n        vector<Action> res;\n        int cur = G;\n        while (cur != S) {\n            uint8_t code = prevOp[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prev[cur];\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    // Local BFS with toggles on at most KMAX candidate cells.\n    // Returns empty if not found under depth limit.\n    vector<Action> shortestLocalWithToggles(pair<int,int> s, pair<int,int> g, int baselineLen) const {\n        int Spos = posId(s.first, s.second);\n        int Gpos = posId(g.first, g.second);\n\n        // If baseline is tiny, improvement is impossible.\n        if (baselineLen <= 1) return {};\n\n        // Candidate priority grid\n        int pr[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) pr[i][j] = -1;\n\n        auto addCand = [&](int x, int y, int p) {\n            if (!inside(x, y)) return;\n            // avoid putting blocks on targets (robustness)\n            if (isTarget[x][y]) return;\n            pr[x][y] = max(pr[x][y], p);\n        };\n\n        int sx = s.first, sy = s.second;\n        int gx = g.first, gy = g.second;\n\n        // Near goal (strong)\n        for (int d = 0; d < 4; d++) addCand(gx + di[d], gy + dj[d], 100);\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            if (abs(dx) + abs(dy) <= 2) addCand(gx + dx, gy + dy, 80);\n        }\n        // Existing blocks near goal (allow removing)\n        for (int dx = -3; dx <= 3; dx++) for (int dy = -3; dy <= 3; dy++) {\n            int x = gx + dx, y = gy + dy;\n            if (!inside(x,y)) continue;\n            if (blockg[x][y] && !isTarget[x][y]) addCand(x, y, 75);\n        }\n\n        // L-shape intersections\n        int p1x = sx, p1y = gy;\n        int p2x = gx, p2y = sy;\n        for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {\n            addCand(p1x + dx, p1y + dy, 60);\n            addCand(p2x + dx, p2y + dy, 60);\n        }\n\n        // Near start (moderate)\n        for (int d = 0; d < 4; d++) addCand(sx + di[d], sy + dj[d], 55);\n        // Existing blocks near start (allow removing)\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            int x = sx + dx, y = sy + dy;\n            if (!inside(x,y)) continue;\n            if (blockg[x][y] && !isTarget[x][y]) addCand(x, y, 50);\n        }\n\n        // Collect top KMAX\n        struct C { int p,x,y; };\n        vector<C> cand;\n        cand.reserve(N*N);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (pr[i][j] >= 0) cand.push_back({pr[i][j], i, j});\n        }\n        sort(cand.begin(), cand.end(), [](const C& a, const C& b){\n            if (a.p != b.p) return a.p > b.p;\n            if (a.x != b.x) return a.x < b.x;\n            return a.y < b.y;\n        });\n        if ((int)cand.size() > KMAX) cand.resize(KMAX);\n\n        int K = (int)cand.size();\n        if (K == 0) return {};\n\n        // local index map\n        int idx[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) idx[i][j] = -1;\n        for (int t = 0; t < K; t++) idx[cand[t].x][cand[t].y] = t;\n\n        // initial mask from global\n        int initMask = 0;\n        for (int t = 0; t < K; t++) {\n            if (blockg[cand[t].x][cand[t].y]) initMask |= (1 << t);\n        }\n\n        // popcount table for this K\n        int MSZ = 1 << K;\n        vector<uint8_t> pop(MSZ, 0);\n        for (int m = 1; m < MSZ; m++) pop[m] = pop[m >> 1] + (m & 1);\n\n        int baseBlocks = totalBlocks - pop[initMask]; // blocks outside candidate set\n\n        auto isBlocked = [&](int x, int y, int mask) -> bool {\n            if (!inside(x, y)) return true;\n            int t = idx[x][y];\n            if (t >= 0) return (mask >> t) & 1;\n            return blockg[x][y];\n        };\n\n        auto slideStop = [&](int x, int y, int dir, int mask) -> int {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[dir], ty = ny + dj[dir];\n                if (!inside(tx, ty)) break;\n                if (isBlocked(tx, ty, mask)) break;\n                nx = tx; ny = ty;\n            }\n            return posId(nx, ny);\n        };\n\n        int limit = baselineLen - 1;\n        if (limit < 0) return {};\n\n        int STATES = (N*N) * MSZ;\n        vector<int16_t> dist(STATES, -1);\n        vector<int32_t> prev(STATES, -1);\n        vector<uint8_t> prevOp(STATES, 255);\n\n        auto sid = [&](int mask, int pos) { return mask * (N*N) + pos; };\n\n        vector<int> q;\n        q.reserve(min(STATES, 2000000)); // heuristic reserve\n        int s0 = sid(initMask, Spos);\n        dist[s0] = 0;\n        q.push_back(s0);\n        size_t head = 0;\n\n        int goalState = -1;\n\n        while (head < q.size()) {\n            int v = q[head++];\n            int dcur = dist[v];\n            if (dcur > limit) continue;\n\n            int mask = v / (N*N);\n            int pos = v % (N*N);\n            if (pos == Gpos) { goalState = v; break; }\n\n            auto [x, y] = idPos(pos);\n\n            // Move / Slide\n            for (int dd = 0; dd < 4; dd++) {\n                // Move\n                int mx = x + di[dd], my = y + dj[dd];\n                if (inside(mx, my) && !isBlocked(mx, my, mask)) {\n                    int to = sid(mask, posId(mx, my));\n                    if (dist[to] == -1) {\n                        dist[to] = dcur + 1;\n                        prev[to] = v;\n                        prevOp[to] = (0 * 4 + dd);\n                        q.push_back(to);\n                    }\n                }\n                // Slide\n                int spos = slideStop(x, y, dd, mask);\n                if (spos != pos) {\n                    int to = sid(mask, spos);\n                    if (dist[to] == -1) {\n                        dist[to] = dcur + 1;\n                        prev[to] = v;\n                        prevOp[to] = (1 * 4 + dd);\n                        q.push_back(to);\n                    }\n                }\n            }\n\n            // Alter (toggle adjacent candidate cell only)\n            for (int dd = 0; dd < 4; dd++) {\n                int ax = x + di[dd], ay = y + dj[dd];\n                if (!inside(ax, ay)) continue;\n                int t = idx[ax][ay];\n                if (t < 0) continue; // only candidate cells\n                // (targets were excluded from candidates)\n                int nmask = mask ^ (1 << t);\n\n                if (baseBlocks + pop[nmask] > MAX_BLOCKS) continue;\n\n                int to = sid(nmask, pos);\n                if (dist[to] == -1) {\n                    dist[to] = dcur + 1;\n                    prev[to] = v;\n                    prevOp[to] = (2 * 4 + dd);\n                    q.push_back(to);\n                }\n            }\n        }\n\n        if (goalState == -1) return {};\n\n        vector<Action> res;\n        int cur = goalState;\n        while (cur != s0) {\n            uint8_t code = prevOp[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prev[cur];\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    void applyAction(pair<int,int>& cur, const Action& ac) {\n        int d = 0;\n        while (d < 4 && dirc[d] != ac.d) d++;\n        int x = cur.first, y = cur.second;\n\n        if (ac.a == 'M') {\n            int nx = x + di[d], ny = y + dj[d];\n            // assume legal\n            cur = {nx, ny};\n        } else if (ac.a == 'S') {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[d], ty = ny + dj[d];\n                if (!inside(tx, ty)) break;\n                if (blockg[tx][ty]) break;\n                nx = tx; ny = ty;\n            }\n            cur = {nx, ny};\n        } else if (ac.a == 'A') {\n            int ax = x + di[d], ay = y + dj[d];\n            // assume legal\n            bool before = blockg[ax][ay];\n            blockg[ax][ay] = !blockg[ax][ay];\n            if (!before && blockg[ax][ay]) totalBlocks++;\n            if (before && !blockg[ax][ay]) totalBlocks--;\n        }\n    }\n\n    void solve() {\n        pair<int,int> cur = P[0];\n\n        for (int k = 0; k < M-1; k++) {\n            pair<int,int> goal = P[k+1];\n\n            // Baseline shortest with fixed blocks (Move+Slide)\n            vector<Action> base = shortestFixed(cur, goal);\n            int baseLen = (int)base.size();\n\n            // Try local improvement (Move+Slide+Alter on small set)\n            vector<Action> improved = shortestLocalWithToggles(cur, goal, baseLen);\n\n            vector<Action> use;\n            if (!improved.empty() && (int)improved.size() < baseLen) use = improved;\n            else use = base;\n\n            // Apply actions to global state\n            for (auto &ac : use) {\n                answer.push_back(ac);\n                applyAction(cur, ac);\n            }\n\n            // Ensure we reached the next target\n            // (If not, fall back to safety: but normally should always match.)\n            if (cur != goal) {\n                // emergency fallback: force with baseline (should be rare)\n                vector<Action> fb = shortestFixed(cur, goal);\n                for (auto &ac : fb) {\n                    answer.push_back(ac);\n                    applyAction(cur, ac);\n                }\n            }\n\n            // Hard cap (must be <= 1600). If exceeded, stop (still outputs legal prefix).\n            if ((int)answer.size() >= 2*N*M) break;\n        }\n\n        // Output\n        int T = (int)answer.size();\n        if (T > 2*N*M) T = 2*N*M;\n        for (int i = 0; i < T; i++) {\n            cout << answer[i].a << ' ' << answer[i].d << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    cin >> s.N >> s.M;\n    s.P.resize(s.M);\n    for (int k = 0; k < s.M; k++) {\n        int x, y;\n        cin >> x >> y;\n        s.P[k] = {x, y};\n    }\n    for (auto &p : s.P) s.isTarget[p.first][p.second] = true;\n\n    s.solve();\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect {\n    int a, b, c, d; // [a,c) x [b,d)\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    // inclusive\n    int rand_int(int l, int r) {\n        if (l > r) return l;\n        uint64_t range = (uint64_t)(r - l + 1);\n        return l + (int)(next_u64() % range);\n    }\n    double rand01() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\nstruct Solver {\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<Rect> rect;\n    vector<double> p;     // current satisfaction per rect\n    double sumP = 0.0;\n\n    SplitMix64 rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n); y.resize(n); r.resize(n);\n        for (int i = 0; i < n; i++) cin >> x[i] >> y[i] >> r[i];\n\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = SplitMix64(seed);\n\n        rect.resize(n);\n        for (int i = 0; i < n; i++) {\n            rect[i] = Rect{x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        p.assign(n, 0.0);\n        recompute_all_scores();\n    }\n\n    long long area(const Rect& R) const {\n        return 1LL * (R.c - R.a) * (R.d - R.b);\n    }\n\n    bool contains_point(int i, const Rect& R) const {\n        return (R.a <= x[i] && x[i] < R.c && R.b <= y[i] && y[i] < R.d);\n    }\n\n    double satisfaction(int i, const Rect& R) const {\n        if (!contains_point(i, R)) return 0.0;\n        long long s = area(R);\n        long long ri = r[i];\n        long long mn = min(ri, s);\n        long long mx = max(ri, s);\n        double ratio = (double)mn / (double)mx;\n        double t = 1.0 - ratio;\n        return 1.0 - t * t;\n    }\n\n    void recompute_all_scores() {\n        sumP = 0.0;\n        for (int i = 0; i < n; i++) {\n            p[i] = satisfaction(i, rect[i]);\n            sumP += p[i];\n        }\n    }\n\n    // For rectangle i, compute nearest blockers in x-direction given its current y-interval.\n    // leftLimit: maximum c_j among rectangles with y-overlap and located to the left (c_j <= a_i)\n    // rightLimit: minimum a_j among rectangles with y-overlap and located to the right (a_j >= c_i)\n    void compute_x_limits(int i, int &leftLimit, int &rightLimit) const {\n        const Rect& R = rect[i];\n        leftLimit = 0;\n        rightLimit = 10000;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = rect[j];\n            if (!overlap1D(R.b, R.d, Q.b, Q.d)) continue; // no y-overlap => cannot collide by x move\n            if (Q.c <= R.a) leftLimit = max(leftLimit, Q.c);\n            if (R.c <= Q.a) rightLimit = min(rightLimit, Q.a);\n        }\n    }\n\n    // For rectangle i, compute nearest blockers in y-direction given its current x-interval.\n    void compute_y_limits(int i, int &downLimit, int &upLimit) const {\n        const Rect& R = rect[i];\n        downLimit = 0;\n        upLimit = 10000;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = rect[j];\n            if (!overlap1D(R.a, R.c, Q.a, Q.c)) continue; // no x-overlap => cannot collide by y move\n            if (Q.d <= R.b) downLimit = max(downLimit, Q.d);\n            if (R.d <= Q.b) upLimit = min(upLimit, Q.b);\n        }\n    }\n\n    // Feasible inclusive range for one side move; returns false if no move possible (range only equals current).\n    // dir: 0=left(a),1=right(c),2=bottom(b),3=top(d)\n    bool feasible_range(int i, int dir, int &low, int &high) const {\n        const Rect& R = rect[i];\n        if (dir == 0) {\n            int L, RR; compute_x_limits(i, L, RR);\n            low = L;\n            high = min(x[i], R.c - 1);\n        } else if (dir == 1) {\n            int L, RR; compute_x_limits(i, L, RR);\n            low = max(x[i] + 1, R.a + 1);\n            high = RR;\n        } else if (dir == 2) {\n            int D, U; compute_y_limits(i, D, U);\n            low = D;\n            high = min(y[i], R.d - 1);\n        } else {\n            int D, U; compute_y_limits(i, D, U);\n            low = max(y[i] + 1, R.b + 1);\n            high = U;\n        }\n        if (low > high) return false;\n        return true;\n    }\n\n    int desired_side_value(int i, int dir, int low, int high) const {\n        const Rect& R = rect[i];\n        long long ri = r[i];\n        if (dir == 0 || dir == 1) {\n            int h = R.d - R.b;\n            long long desiredW = (ri + h / 2) / h;\n            desiredW = max<long long>(1, min<long long>(10000, desiredW));\n            if (dir == 0) {\n                long long desA = (long long)R.c - desiredW;\n                desA = max<long long>(low, min<long long>(high, desA));\n                return (int)desA;\n            } else {\n                long long desC = (long long)R.a + desiredW;\n                desC = max<long long>(low, min<long long>(high, desC));\n                return (int)desC;\n            }\n        } else {\n            int w = R.c - R.a;\n            long long desiredH = (ri + w / 2) / w;\n            desiredH = max<long long>(1, min<long long>(10000, desiredH));\n            if (dir == 2) {\n                long long desB = (long long)R.d - desiredH;\n                desB = max<long long>(low, min<long long>(high, desB));\n                return (int)desB;\n            } else {\n                long long desD = (long long)R.b + desiredH;\n                desD = max<long long>(low, min<long long>(high, desD));\n                return (int)desD;\n            }\n        }\n    }\n\n    Rect with_side(const Rect& R, int dir, int val) const {\n        Rect T = R;\n        if (dir == 0) T.a = val;\n        else if (dir == 1) T.c = val;\n        else if (dir == 2) T.b = val;\n        else T.d = val;\n        return T;\n    }\n\n    // Greedy single-rectangle improvement: try setting one side to (desired,low,high) and take best improvement.\n    bool greedy_improve_one(int i) {\n        double cur = p[i];\n        Rect bestR = rect[i];\n        double best = cur;\n\n        for (int dir = 0; dir < 4; dir++) {\n            int low, high;\n            if (!feasible_range(i, dir, low, high)) continue;\n\n            int curVal = (dir==0? rect[i].a : dir==1? rect[i].c : dir==2? rect[i].b : rect[i].d);\n            if (low == high && low == curVal) continue;\n\n            int des = desired_side_value(i, dir, low, high);\n            int candidates[3] = {des, low, high};\n            for (int k = 0; k < 3; k++) {\n                int v = candidates[k];\n                if (v == curVal) continue;\n                Rect cand = with_side(rect[i], dir, v);\n                // Must remain valid and contain point (range logic should ensure it).\n                if (!contains_point(i, cand)) continue;\n                if (cand.a < 0 || cand.b < 0 || cand.c > 10000 || cand.d > 10000) continue;\n                if (cand.a >= cand.c || cand.b >= cand.d) continue;\n                double sc = satisfaction(i, cand);\n                if (sc > best + 1e-12) {\n                    best = sc;\n                    bestR = cand;\n                }\n            }\n        }\n\n        if (best > cur + 1e-12) {\n            rect[i] = bestR;\n            sumP += (best - p[i]);\n            p[i] = best;\n            return true;\n        }\n        return false;\n    }\n\n    void greedy_init() {\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) { return r[a] > r[b]; });\n\n        // Several passes until no change.\n        for (int pass = 0; pass < 30; pass++) {\n            bool any = false;\n            for (int idx = 0; idx < n; idx++) {\n                int i = order[idx];\n                // a few local steps\n                for (int rep = 0; rep < 3; rep++) {\n                    if (!greedy_improve_one(i)) break;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        // Random greedy polishing\n        for (int it = 0; it < 40000; it++) {\n            int i = (int)(rng.next_u32() % n);\n            greedy_improve_one(i);\n        }\n    }\n\n    void simulated_annealing(double timeLimitSec) {\n        auto start = chrono::steady_clock::now();\n        auto elapsedSec = [&]() -> double {\n            return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        };\n\n        vector<Rect> bestRect = rect;\n        vector<double> bestP = p;\n        double bestSum = sumP;\n\n        const double T0 = 0.05;\n        const double T1 = 0.001;\n\n        long long iterations = 0;\n\n        while (true) {\n            double t = elapsedSec();\n            if (t >= timeLimitSec) break;\n            double prog = t / timeLimitSec;\n            double T = T0 * pow(T1 / T0, prog);\n\n            int i = (int)(rng.next_u32() % n);\n            int dir = (int)(rng.next_u32() & 3);\n\n            int low, high;\n            if (!feasible_range(i, dir, low, high)) continue;\n\n            int curVal = (dir==0? rect[i].a : dir==1? rect[i].c : dir==2? rect[i].b : rect[i].d);\n            if (low == high) continue;\n            if (curVal < low || curVal > high) {\n                // Shouldn't happen, but guard.\n                curVal = max(low, min(high, curVal));\n            }\n\n            int des = desired_side_value(i, dir, low, high);\n\n            int candVal;\n            if (rng.rand01() < 0.75) {\n                int span = max(1, (high - low) / 10);\n                candVal = des + rng.rand_int(-span, span);\n                candVal = max(low, min(high, candVal));\n            } else {\n                candVal = rng.rand_int(low, high);\n            }\n            if (candVal == curVal) continue;\n\n            Rect oldR = rect[i];\n            double oldP = p[i];\n\n            Rect newR = with_side(oldR, dir, candVal);\n            if (!contains_point(i, newR)) continue;\n            if (newR.a >= newR.c || newR.b >= newR.d) continue;\n\n            double newP = satisfaction(i, newR);\n            double delta = newP - oldP;\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double prob = exp(delta / T);\n                if (rng.rand01() < prob) accept = true;\n            }\n\n            if (accept) {\n                rect[i] = newR;\n                p[i] = newP;\n                sumP += delta;\n\n                if (sumP > bestSum + 1e-12) {\n                    bestSum = sumP;\n                    bestRect = rect;\n                    bestP = p;\n                }\n            }\n\n            iterations++;\n        }\n\n        rect = bestRect;\n        p = bestP;\n        sumP = bestSum;\n    }\n\n    void solve() {\n        // 1) Greedy initialization (fast, improves a lot over 1x1)\n        greedy_init();\n\n        // 2) SA refinement\n        simulated_annealing(4.90);\n\n        // Output\n        for (int i = 0; i < n; i++) {\n            cout << rect[i].a << ' ' << rect[i].b << ' ' << rect[i].c << ' ' << rect[i].d << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50, W = 50, N = H * W;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // 2^53\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Result {\n    vector<int> path; // sequence of square indices\n    int score = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    cin >> si >> sj;\n\n    vector<int> tile(N);\n    int maxTile = 0;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int t;\n            cin >> t;\n            tile[i * W + j] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    int M = maxTile + 1;\n\n    vector<int> val(N);\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int p;\n            cin >> p;\n            val[i * W + j] = p;\n        }\n    }\n\n    // Build adjacency between squares BUT only if they are in different tiles\n    array<vector<int>, N> adj;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int u = i * W + j;\n            static const int di[4] = {-1, 1, 0, 0};\n            static const int dj[4] = {0, 0, -1, 1};\n            for (int k = 0; k < 4; k++) {\n                int ni = i + di[k], nj = j + dj[k];\n                if (ni < 0 || ni >= H || nj < 0 || nj >= W) continue;\n                int v = ni * W + nj;\n                if (tile[u] == tile[v]) continue; // moving within same tile is forbidden anyway\n                adj[u].push_back(v);\n            }\n        }\n    }\n\n    const int start = si * W + sj;\n\n    // stamp-based \"used tile\" set\n    vector<int> usedStamp(M, 0);\n    int stamp = 0;\n\n    auto build_from_prefix = [&](const vector<int>& prefix, double alpha, double gamma, XorShift64 &rng) -> Result {\n        stamp++;\n        int st = stamp;\n\n        Result res;\n        res.path = prefix;\n        res.path.reserve(N);\n\n        int scoreSum = 0;\n        for (int v : prefix) {\n            usedStamp[tile[v]] = st;\n            scoreSum += val[v];\n        }\n\n        auto deg_unvisited = [&](int v) -> int {\n            int d = 0;\n            for (int to : adj[v]) {\n                if (usedStamp[tile[to]] != st) d++;\n            }\n            return d;\n        };\n\n        int cur = res.path.back();\n        while (true) {\n            // candidates up to 4\n            struct Cand { int v; double e; };\n            Cand cands[4];\n            int m = 0;\n\n            for (int nb : adj[cur]) {\n                int tnb = tile[nb];\n                if (usedStamp[tnb] == st) continue;\n\n                int deg1 = 0;\n                for (int nn : adj[nb]) {\n                    if (usedStamp[tile[nn]] != st) deg1++;\n                }\n\n                // 2-step lookahead: best next-next value after choosing nb\n                double best2 = 0.0;\n                for (int nn : adj[nb]) {\n                    int tnn = tile[nn];\n                    if (usedStamp[tnn] == st) continue;\n                    // degree at nn AFTER visiting nb (so tile[nb] becomes forbidden)\n                    int deg2 = 0;\n                    for (int x : adj[nn]) {\n                        int tx = tile[x];\n                        if (tx == tnb) continue;\n                        if (usedStamp[tx] != st) deg2++;\n                    }\n                    double cand2 = val[nn] + alpha * deg2;\n                    if (cand2 > best2) best2 = cand2;\n                }\n\n                double e = val[nb] + alpha * deg1 + gamma * best2;\n\n                // discourage immediate dead ends unless necessary\n                if (deg1 == 0) e -= 35.0;\n\n                // tiny noise for tie-breaking / diversification\n                e += rng.next_double() * 1e-3;\n\n                cands[m++] = {nb, e};\n            }\n\n            if (m == 0) break;\n\n            // sort m<=4 by e descending (simple selection)\n            for (int i = 0; i < m; i++) {\n                int best = i;\n                for (int j = i + 1; j < m; j++) {\n                    if (cands[j].e > cands[best].e) best = j;\n                }\n                swap(cands[i], cands[best]);\n            }\n\n            int pickRank = 0;\n            if (m >= 2) {\n                double u = rng.next_double();\n                if (u < 0.75) pickRank = 0;\n                else if (u < 0.93) pickRank = 1;\n                else pickRank = min(2, m - 1);\n            }\n\n            int nxt = cands[pickRank].v;\n            usedStamp[tile[nxt]] = st;\n            res.path.push_back(nxt);\n            scoreSum += val[nxt];\n            cur = nxt;\n        }\n\n        res.score = scoreSum;\n        return res;\n    };\n\n    auto now = chrono::steady_clock::now;\n    const double TIME_LIMIT = 1.95;\n    auto t0 = now();\n\n    XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multi-start randomized greedy to get a good initial best\n    Result best;\n    best.path = {start};\n    best.score = val[start];\n\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > 0.25) break;\n\n        double alpha = 8.0 + 18.0 * rng.next_double();  // [8,26]\n        double gamma = 0.10 + 0.55 * rng.next_double(); // [0.10,0.65]\n        Result r = build_from_prefix(vector<int>{start}, alpha, gamma, rng);\n        if (r.score > best.score) best = std::move(r);\n    }\n\n    // Simulated annealing with cut-and-regrow\n    Result cur = best;\n\n    int iter = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > TIME_LIMIT) break;\n        iter++;\n\n        // occasionally restart from best to keep search stable\n        if (iter % 450 == 0) cur = best;\n\n        int L = (int)cur.path.size();\n        int k = 0;\n        if (L <= 1) {\n            k = 0;\n        } else {\n            double u = rng.next_double();\n            if (u < 0.70) {\n                int lo = max(0, L - 1 - 220);\n                k = rng.next_int(lo, L - 1);\n            } else {\n                k = rng.next_int(0, L - 1);\n            }\n        }\n\n        vector<int> prefix;\n        prefix.reserve(k + 1);\n        prefix.insert(prefix.end(), cur.path.begin(), cur.path.begin() + (k + 1));\n\n        double alpha = 7.0 + 20.0 * rng.next_double();  // [7,27]\n        double gamma = 0.05 + 0.70 * rng.next_double(); // [0.05,0.75]\n        Result nxt = build_from_prefix(prefix, alpha, gamma, rng);\n\n        int delta = nxt.score - cur.score;\n\n        // temperature schedule by time\n        double tr = elapsed / TIME_LIMIT;\n        double T0 = 350.0, Tend = 2.0;\n        double T = T0 * pow(Tend / T0, tr);\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (accept) cur = std::move(nxt);\n        if (cur.score > best.score) best = cur;\n    }\n\n    // Output path as directions\n    string out;\n    out.reserve(best.path.size() ? best.path.size() - 1 : 0);\n    for (int i = 1; i < (int)best.path.size(); i++) {\n        int a = best.path[i - 1], b = best.path[i];\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (bi == ai - 1 && bj == aj) out.push_back('U');\n        else if (bi == ai + 1 && bj == aj) out.push_back('D');\n        else if (bi == ai && bj == aj - 1) out.push_back('L');\n        else if (bi == ai && bj == aj + 1) out.push_back('R');\n        else {\n            // should never happen\n            // fallback: output what we have\n            break;\n        }\n    }\n\n    cout << out << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horiz; // true: horizontal h[i][j] between (i,j)-(i,j+1), false: vertical v[i][j] between (i,j)-(i+1,j)\n    int i, j;\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int HW = 29; // horizontal edges per row\nstatic constexpr int VH = 29; // vertical edges per col\n\nstruct Solver {\n    // Estimated weights\n    double h[N][HW];\n    double v[VH][N];\n\n    // Visit counts (for exploration bonus)\n    int hc[N][HW];\n    int vc[VH][N];\n\n    vector<EdgeRef> last_edges;\n    double last_pred = 0.0;\n    int k = 0; // number of processed feedbacks\n\n    Solver() {\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n            h[i][j] = 5000.0;\n            hc[i][j] = 0;\n        }\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n            v[i][j] = 5000.0;\n            vc[i][j] = 0;\n        }\n    }\n\n    static inline double clampd(double x, double lo, double hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    inline double &edgeRef(const EdgeRef &e) {\n        return e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n    }\n    inline int &cntRef(const EdgeRef &e) {\n        return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n    }\n\n    // Base (non-exploration) estimated weight for move u->w\n    inline double baseWeight(int u, int w, EdgeRef &eref_out) {\n        int ui = u / N, uj = u % N;\n        int wi = w / N, wj = w % N;\n        if (ui == wi) {\n            // horizontal\n            if (wj == uj + 1) {\n                eref_out = {true, ui, uj};\n                return h[ui][uj];\n            } else {\n                // wj == uj - 1\n                eref_out = {true, ui, wj};\n                return h[ui][wj];\n            }\n        } else {\n            // vertical\n            if (wi == ui + 1) {\n                eref_out = {false, ui, uj};\n                return v[ui][uj];\n            } else {\n                // wi == ui - 1\n                eref_out = {false, wi, uj};\n                return v[wi][uj];\n            }\n        }\n    }\n\n    // Exploration-modified weight for Dijkstra at query index qk\n    inline double planWeight(const EdgeRef &e, int qk) const {\n        const double base = e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n        const int cnt = e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n\n        // Exploration fades out in first ~300 queries\n        double phase = 0.0;\n        if (qk < 300) phase = (300.0 - qk) / 300.0; // 1 -> 0\n        double explore = 0.6 * phase; // hyperparameter\n\n        // Make rarely-used edges slightly cheaper early\n        double denom = 1.0 + explore / sqrt(cnt + 1.0);\n        double w = base / denom;\n\n        // Keep weights positive and reasonable\n        w = clampd(w, 500.0, 12000.0);\n        return w;\n    }\n\n    // Dijkstra to get a path (full 4-neighbor), returns node list s..t\n    vector<int> shortestPathNodes(int si, int sj, int ti, int tj, int qk, double explore_scale_override = -1.0) {\n        int s = si * N + sj;\n        int t = ti * N + tj;\n\n        vector<double> dist(N * N, 1e100);\n        vector<int> prev(N * N, -1);\n\n        using P = pair<double,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == t) break;\n\n            int ui = u / N, uj = u % N;\n            auto relax = [&](int w) {\n                EdgeRef e;\n                // Need EdgeRef to compute weight; baseWeight fills e\n                (void)baseWeight(u, w, e);\n                double ww;\n\n                if (explore_scale_override >= 0.0) {\n                    // same shape as planWeight but scale can be forced smaller\n                    const double base = e.horiz ? h[e.i][e.j] : v[e.i][e.j];\n                    const int cnt = e.horiz ? hc[e.i][e.j] : vc[e.i][e.j];\n                    double phase = 0.0;\n                    if (qk < 300) phase = (300.0 - qk) / 300.0;\n                    double explore = explore_scale_override * phase;\n                    double denom = 1.0 + explore / sqrt(cnt + 1.0);\n                    ww = clampd(base / denom, 500.0, 12000.0);\n                } else {\n                    ww = planWeight(e, qk);\n                }\n\n                double nd = d + ww;\n                if (nd < dist[w]) {\n                    dist[w] = nd;\n                    prev[w] = u;\n                    pq.push({nd, w});\n                }\n            };\n\n            if (uj + 1 < N) relax(u + 1);\n            if (uj - 1 >= 0) relax(u - 1);\n            if (ui + 1 < N) relax(u + N);\n            if (ui - 1 >= 0) relax(u - N);\n        }\n\n        // reconstruct\n        vector<int> nodes;\n        int cur = t;\n        while (cur != -1) {\n            nodes.push_back(cur);\n            if (cur == s) break;\n            cur = prev[cur];\n        }\n        reverse(nodes.begin(), nodes.end());\n        return nodes;\n    }\n\n    // Build path string and record last_edges + last_pred\n    string buildPathAndRecord(const vector<int> &nodes) {\n        last_edges.clear();\n        last_pred = 0.0;\n        string path;\n        path.reserve(nodes.size() ? nodes.size()-1 : 0);\n\n        for (int idx = 0; idx + 1 < (int)nodes.size(); idx++) {\n            int a = nodes[idx];\n            int b = nodes[idx + 1];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            if (bi == ai && bj == aj + 1) path.push_back('R');\n            else if (bi == ai && bj == aj - 1) path.push_back('L');\n            else if (bi == ai + 1 && bj == aj) path.push_back('D');\n            else if (bi == ai - 1 && bj == aj) path.push_back('U');\n            else {\n                // should never happen\n                path.push_back('R');\n            }\n\n            EdgeRef e;\n            double w = baseWeight(a, b, e);\n            last_edges.push_back(e);\n            last_pred += w;\n        }\n        last_pred = max(last_pred, 1.0); // safety\n        return path;\n    }\n\n    string query(int si, int sj, int ti, int tj) {\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        // Primary attempt with exploration\n        vector<int> nodes = shortestPathNodes(si, sj, ti, tj, k);\n        // Safety: avoid crazy-long exploratory detours\n        if ((int)nodes.size() - 1 > manhattan + 60) {\n            nodes = shortestPathNodes(si, sj, ti, tj, k, /*explore_scale_override=*/0.2);\n        }\n        if ((int)nodes.size() - 1 > manhattan + 80) {\n            nodes = shortestPathNodes(si, sj, ti, tj, k, /*explore_scale_override=*/0.0);\n        }\n\n        return buildPathAndRecord(nodes);\n    }\n\n    void smoothOnce(double s) {\n        // Smooth horizontal along each row\n        for (int i = 0; i < N; i++) {\n            double tmp[HW];\n            for (int j = 0; j < HW; j++) {\n                double a = h[i][j];\n                double b = (j > 0 ? h[i][j-1] : h[i][j]);\n                double c = (j + 1 < HW ? h[i][j+1] : h[i][j]);\n                tmp[j] = (a + b + c) / 3.0;\n            }\n            for (int j = 0; j < HW; j++) {\n                h[i][j] = (1.0 - s) * h[i][j] + s * tmp[j];\n                h[i][j] = clampd(h[i][j], 500.0, 12000.0);\n            }\n        }\n\n        // Smooth vertical along each column\n        for (int j = 0; j < N; j++) {\n            double tmp[VH];\n            for (int i = 0; i < VH; i++) {\n                double a = v[i][j];\n                double b = (i > 0 ? v[i-1][j] : v[i][j]);\n                double c = (i + 1 < VH ? v[i+1][j] : v[i][j]);\n                tmp[i] = (a + b + c) / 3.0;\n            }\n            for (int i = 0; i < VH; i++) {\n                v[i][j] = (1.0 - s) * v[i][j] + s * tmp[i];\n                v[i][j] = clampd(v[i][j], 500.0, 12000.0);\n            }\n        }\n    }\n\n    void feedback(long long observed) {\n        // observed ~= last_pred * noise, noise in [0.9,1.1]\n        double ratio = (double)observed / last_pred;\n        ratio = clampd(ratio, 0.85, 1.18); // robust against outliers\n\n        // learning rate schedule: larger early, smaller later\n        double t = (double)k / 1000.0;\n        double lr = 0.35 * (1.0 - t) + 0.08; // ~0.43 -> ~0.08\n        double mul = 1.0 + lr * (ratio - 1.0);\n\n        // Update only used edges (and increase counts)\n        for (auto &e : last_edges) {\n            double &w = edgeRef(e);\n            int &c = cntRef(e);\n            w *= mul;\n            w = clampd(w, 500.0, 12000.0);\n            c++;\n        }\n\n        // Optional: tiny global scaling early to fix overall magnitude faster\n        if (k < 50) {\n            double glr = 0.02;\n            double gmul = 1.0 + glr * (ratio - 1.0);\n            for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n                h[i][j] = clampd(h[i][j] * gmul, 500.0, 12000.0);\n            }\n            for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n                v[i][j] = clampd(v[i][j] * gmul, 500.0, 12000.0);\n            }\n        }\n\n        // Periodic smoothing (matches \u201cmostly constant with local noise\u201d)\n        if (k % 5 == 4) {\n            smoothOnce(0.05);\n        }\n\n        k++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; q++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        string path = solver.query(si, sj, ti, tj);\n        cout << path << \"\\n\" << flush;\n\n        long long res;\n        cin >> res;\n        solver.feedback(res);\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr uint8_t DOT = 8; // internal '.' marker (used only in final pruning)\n\n// ---------- RNG (splitmix64) ----------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Hasher {\n    size_t operator()(uint64_t x) const noexcept {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        x ^= (x >> 31);\n        return (size_t)x;\n    }\n};\n\nusing FlatMap = boost::unordered_flat_map<uint64_t, int, Hasher>;\n\n// code = (len<<36) | bits, bits uses 3 bits/char, left-to-right.\nstatic inline uint64_t encodeVec(const vector<uint8_t>& v, int st, int len) {\n    uint64_t bits = 0;\n    for (int i = 0; i < len; i++) bits = (bits << 3) | (uint64_t)v[st + i];\n    return (uint64_t(len) << 36) | bits;\n}\nstatic inline uint64_t encodeFull(const vector<uint8_t>& v) {\n    return encodeVec(v, 0, (int)v.size());\n}\nstatic inline vector<uint8_t> decodeCode(uint64_t code) {\n    int len = int(code >> 36);\n    vector<uint8_t> v(len);\n    uint64_t bits = code & ((len == 0) ? 0ULL : ((1ULL << (3 * len)) - 1ULL));\n    for (int i = len - 1; i >= 0; i--) {\n        v[i] = uint8_t(bits & 7ULL);\n        bits >>= 3;\n    }\n    return v;\n}\n\nstruct CodeBook {\n    int minLen = 2, maxLen = 12;\n    FlatMap code2idx;\n    vector<int> weight;                 // weight per unique code\n    vector<uint64_t> codes;             // code per idx\n    vector<vector<uint8_t>> pattern;    // decoded pattern (optional)\n    long long totalWeight = 0;          // sum weights\n};\n\nstatic CodeBook makeCodeBook(const FlatMap& wmap, int minLen, int maxLen, bool storePattern) {\n    CodeBook book;\n    book.minLen = minLen;\n    book.maxLen = maxLen;\n    book.code2idx.reserve(wmap.size() * 2 + 8);\n    book.weight.reserve(wmap.size());\n    book.codes.reserve(wmap.size());\n\n    int idx = 0;\n    long long sum = 0;\n    for (auto &kv : wmap) {\n        uint64_t code = kv.first;\n        int w = kv.second;\n        book.code2idx.emplace(code, idx++);\n        book.codes.push_back(code);\n        book.weight.push_back(w);\n        sum += w;\n    }\n    book.totalWeight = sum;\n\n    if (storePattern) {\n        book.pattern.resize(book.codes.size());\n        for (int i = 0; i < (int)book.codes.size(); i++) book.pattern[i] = decodeCode(book.codes[i]);\n    }\n    return book;\n}\n\n// ---------- SA state with incremental update ----------\nstruct SAState {\n    array<array<uint8_t, N>, N>* mat = nullptr;\n    const CodeBook* book = nullptr;\n\n    vector<int> occ;              // occ[idx] = total occurrences across all 40 lines\n    long long score = 0;          // sum weight[idx] for occ[idx] > 0\n\n    array<vector<int>, 40> lineIdx;  // for each line, list of matched idx (with multiplicity)\n    vector<int> buf;                // reusable compute buffer\n\n    inline void getLineSeq(int lineId, uint8_t seq[N]) const {\n        if (lineId < 20) {\n            int r = lineId;\n            for (int c = 0; c < N; c++) seq[c] = (*mat)[r][c];\n        } else {\n            int c = lineId - 20;\n            for (int r = 0; r < N; r++) seq[r] = (*mat)[r][c];\n        }\n    }\n\n    inline void computeLineInto(int lineId, vector<int>& out) const {\n        out.clear();\n        uint8_t seq[N];\n        getLineSeq(lineId, seq);\n\n        const int minL = book->minLen;\n        const int maxL = book->maxLen;\n\n        for (int st = 0; st < N; st++) {\n            uint64_t bits = 0;\n            int pos = st;\n            for (int l = 1; l <= maxL; l++) {\n                uint8_t v = seq[pos];\n                if (v == DOT) break;\n                bits = (bits << 3) | (uint64_t)v;\n                if (l >= minL) {\n                    uint64_t code = (uint64_t(l) << 36) | bits;\n                    auto it = book->code2idx.find(code);\n                    if (it != book->code2idx.end()) out.push_back(it->second);\n                }\n                pos++;\n                if (pos == N) pos = 0;\n            }\n        }\n    }\n\n    // swap lineIdx[lineId] with newVec, and update occ/score accordingly.\n    inline void replaceSwapLine(int lineId, vector<int>& newVec) {\n        // remove old\n        for (int idx : lineIdx[lineId]) {\n            int &x = occ[idx];\n            x--;\n            if (x == 0) score -= book->weight[idx];\n        }\n        // add new\n        for (int idx : newVec) {\n            int &x = occ[idx];\n            if (x == 0) score += book->weight[idx];\n            x++;\n        }\n        lineIdx[lineId].swap(newVec); // newVec becomes old content\n    }\n\n    void init(array<array<uint8_t, N>, N>& m, const CodeBook& b) {\n        mat = &m;\n        book = &b;\n        occ.assign(book->codes.size(), 0);\n        score = 0;\n        for (int lineId = 0; lineId < 40; lineId++) {\n            vector<int> tmp;\n            tmp.reserve(256);\n            computeLineInto(lineId, tmp);\n            lineIdx[lineId] = std::move(tmp);\n            for (int idx : lineIdx[lineId]) {\n                int &x = occ[idx];\n                if (x == 0) score += book->weight[idx];\n                x++;\n            }\n        }\n        buf.clear();\n        buf.reserve(256);\n    }\n};\n\nstruct Solver {\n    int M;\n    vector<vector<uint8_t>> inputs;\n    RNG rng;\n    array<array<uint8_t, N>, N> mat;\n    chrono::steady_clock::time_point startTime;\n\n    explicit Solver(int M) : M(M) {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = RNG(seed);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    inline double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    struct CellCh { int r, c; uint8_t oldv; };\n\n    // Apply a set of cell changes (mat already updated), update SAState incrementally, accept by SA rule, else rollback.\n    bool tryApply(SAState& st, const vector<CellCh>& changes, double T) {\n        if (changes.empty()) return false;\n\n        bool mark[40] = {};\n        int lids[40];\n        int lidCount = 0;\n\n        auto addLine = [&](int id) {\n            if (!mark[id]) {\n                mark[id] = true;\n                lids[lidCount++] = id;\n            }\n        };\n\n        for (auto &ch : changes) {\n            addLine(ch.r);\n            addLine(20 + ch.c);\n        }\n\n        long long oldScore = st.score;\n\n        // swap-based backups, no deep copy of existing line vectors\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n\n        vector<int> tmp;\n        tmp.reserve(256);\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp);           // tmp becomes old vector\n            backups.push_back({lid, std::move(tmp)}); // store old vector\n            tmp.clear();\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            // restore line vectors\n            for (int k = (int)backups.size() - 1; k >= 0; k--) {\n                st.replaceSwapLine(backups[k].first, backups[k].second);\n            }\n            // restore cells\n            for (auto &ch : changes) mat[ch.r][ch.c] = ch.oldv;\n        }\n        return accept;\n    }\n\n    void addSubstrings(FlatMap& w, const vector<uint8_t>& s, int minLen, int maxLen, int base) {\n        int L = (int)s.size();\n        for (int len = minLen; len <= maxLen; len++) {\n            if (len > L) break;\n            int mul = base;\n            // mild length bias (longer k-mers are more informative)\n            mul *= (len * len);\n            for (int st = 0; st + len <= L; st++) {\n                w[encodeVec(s, st, len)] += mul;\n            }\n        }\n    }\n\n    // Segment overwrite move: choose input string (or substring) and write into random cyclic row/col segment.\n    bool doSegmentOverwrite(SAState& st, double T, int minK, int maxK) {\n        int idx = rng.nextInt(0, M - 1);\n        const auto& s = inputs[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n\n        int k;\n        if (rng.nextDouble() < 0.55) {\n            k = min(L, maxK);\n        } else {\n            k = rng.nextInt(minK, min(maxK, L));\n        }\n        int off = rng.nextInt(0, L - k);\n\n        bool vert = (rng.nextInt(0, 1) == 1);\n        int line = rng.nextInt(0, N - 1);\n        int start = rng.nextInt(0, N - 1);\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n\n        if (!vert) {\n            int r = line;\n            for (int t = 0; t < k; t++) {\n                int c = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = line;\n            for (int t = 0; t < k; t++) {\n                int r = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApply(st, changes, T);\n    }\n\n    // Single-cell mutation\n    bool doCellMutate(SAState& st, double T) {\n        int i = rng.nextInt(0, N - 1);\n        int j = rng.nextInt(0, N - 1);\n        uint8_t oldv = mat[i][j];\n        uint8_t nv = oldv;\n        while (nv == oldv) nv = (uint8_t)rng.nextInt(0, 7);\n        mat[i][j] = nv;\n        vector<CellCh> changes = { {i, j, oldv} };\n        return tryApply(st, changes, T);\n    }\n\n    // Impose uncovered full string: pick uncovered code, try a few placements, apply with SA acceptance.\n    bool doImposeUncovered(SAState& st, double T, int trials = 50) {\n        if (st.book->pattern.empty()) return false;\n        if (st.score >= st.book->totalWeight) return false;\n\n        int U = (int)st.occ.size();\n        int target = -1;\n        for (int t = 0; t < 40; t++) {\n            int cand = rng.nextInt(0, U - 1);\n            if (st.occ[cand] == 0) { target = cand; break; }\n        }\n        if (target < 0) return false;\n\n        const auto& pat = st.book->pattern[target];\n        int k = (int)pat.size();\n        if (k < 2) return false;\n\n        bool bestVert = false;\n        int bestLine = 0, bestStart = 0;\n        int bestMismatch = 1e9;\n\n        for (int t = 0; t < trials; t++) {\n            bool vert = (rng.nextInt(0, 1) == 1);\n            int line = rng.nextInt(0, N - 1);\n            int start = rng.nextInt(0, N - 1);\n            int mism = 0;\n            if (!vert) {\n                int r = line;\n                for (int x = 0; x < k; x++) mism += (mat[r][(start + x) % N] != pat[x]);\n            } else {\n                int c = line;\n                for (int x = 0; x < k; x++) mism += (mat[(start + x) % N][c] != pat[x]);\n            }\n            if (mism < bestMismatch) {\n                bestMismatch = mism;\n                bestVert = vert;\n                bestLine = line;\n                bestStart = start;\n                if (bestMismatch == 0) break;\n            }\n        }\n        if (bestMismatch == 0) return false; // already occurs somehow\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n        if (!bestVert) {\n            int r = bestLine;\n            for (int x = 0; x < k; x++) {\n                int c = (bestStart + x) % N;\n                uint8_t nv = pat[x];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = bestLine;\n            for (int x = 0; x < k; x++) {\n                int r = (bestStart + x) % N;\n                uint8_t nv = pat[x];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApply(st, changes, T);\n    }\n\n    void anneal(SAState& st, double tStart, double tEnd,\n                double T0, double T1,\n                double pSeg, double pImpose, int segMinK, int segMaxK, bool allowImpose) {\n        while (true) {\n            double now = elapsedSec();\n            if (now >= tEnd) break;\n            double prog = (now - tStart) / max(1e-9, (tEnd - tStart));\n            prog = min(1.0, max(0.0, prog));\n            double T = T0 * pow(T1 / T0, prog);\n\n            double r = rng.nextDouble();\n            if (allowImpose && r < pImpose) {\n                doImposeUncovered(st, T);\n            } else if (r < pImpose + pSeg) {\n                doSegmentOverwrite(st, T, segMinK, segMaxK);\n            } else {\n                doCellMutate(st, T);\n            }\n        }\n    }\n\n    // Final greedy improvement: accept only if full coverage count increases.\n    void greedyFinishFull(SAState& st, double tEnd) {\n        if (st.book->pattern.empty()) return;\n        while (elapsedSec() < tEnd) {\n            long long before = st.score;\n            // Use low \"temperature\": only accept improvements.\n            // Implement by calling impose and then checking.\n            // We use a dummy very small T and also reject if not improved.\n            // (tryApply inside doImpose can accept negative with SA; avoid that by just re-checking.)\n            array<array<uint8_t, N>, N> backupMat = mat;\n            vector<int> backupOcc = st.occ;\n            long long backupScore = st.score;\n            auto backupLines = st.lineIdx;\n\n            doImposeUncovered(st, /*T*/1e-9, 80);\n            if (st.score <= before) {\n                // rollback\n                mat = backupMat;\n                st.occ = std::move(backupOcc);\n                st.score = backupScore;\n                st.lineIdx = std::move(backupLines);\n                // If we couldn't improve, stop early with some probability to save time\n                if (rng.nextDouble() < 0.25) break;\n            }\n        }\n    }\n\n    void pruneDotsIfAllCovered(const CodeBook& fullBook) {\n        SAState st;\n        st.init(mat, fullBook);\n        if (st.score != fullBook.totalWeight) return;\n\n        vector<int> order(N * N);\n        iota(order.begin(), order.end(), 0);\n        for (int k = (int)order.size() - 1; k > 0; k--) {\n            int r = rng.nextInt(0, k);\n            swap(order[k], order[r]);\n        }\n\n        for (int p : order) {\n            int i = p / N, j = p % N;\n            if (mat[i][j] == DOT) continue;\n            uint8_t oldv = mat[i][j];\n            mat[i][j] = DOT;\n\n            vector<CellCh> changes = { {i, j, oldv} };\n            // accept only if still all covered\n            long long oldScore = st.score;\n            bool ok = tryApply(st, changes, /*T*/1e-12);\n            if (!ok) continue; // reverted by SA rule (shouldn't happen due to T tiny)\n            if (st.score != fullBook.totalWeight) {\n                // force rollback (tryApply accepted; revert manually)\n                // easiest: revert cell and recompute affected lines properly by undoing with another tryApply\n                mat[i][j] = oldv;\n                vector<CellCh> back = { {i, j, DOT} };\n                tryApply(st, back, /*T*/1e9); // accept surely (delta>=0 usually), just to sync\n                // If the accept happened to reject (unlikely), re-init\n                if (mat[i][j] != oldv) {\n                    mat[i][j] = oldv;\n                    st.init(mat, fullBook);\n                }\n            }\n        }\n    }\n\n    void solveAndPrint() {\n        // Slightly better init: sample letters according to global frequency in reads.\n        array<long long, 8> freq{};\n        long long tot = 0;\n        for (auto &s : inputs) for (uint8_t v : s) { freq[v]++; tot++; }\n        if (tot > 0) {\n            vector<double> acc(8);\n            double sum = 0;\n            for (int i = 0; i < 8; i++) sum += (double)freq[i] + 1.0;\n            double cur = 0;\n            for (int i = 0; i < 8; i++) {\n                cur += ((double)freq[i] + 1.0) / sum;\n                acc[i] = cur;\n            }\n            for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n                double r = rng.nextDouble();\n                int v = 0;\n                while (v < 7 && r > acc[v]) v++;\n                mat[i][j] = (uint8_t)v;\n            }\n        }\n\n        // Build phase books:\n        // A: k-mers 3..7 only\n        // B: k-mers 4..8 + full strings with boosted weight\n        // C: full strings only (true objective)\n        FlatMap wA; wA.reserve((size_t)20000);\n        FlatMap wB; wB.reserve((size_t)30000);\n        FlatMap wC; wC.reserve((size_t)2048);\n\n        const int FULL_BOOST = 80; // weight multiplier in phase B\n\n        for (auto &s : inputs) {\n            // full strings for B and C\n            wB[encodeFull(s)] += FULL_BOOST;\n            wC[encodeFull(s)] += 1;\n\n            addSubstrings(wA, s, 3, 7, 1);\n            addSubstrings(wB, s, 4, 8, 1);\n        }\n\n        CodeBook bookA = makeCodeBook(wA, 3, 7, false);\n        CodeBook bookB = makeCodeBook(wB, 2, 12, false);\n        CodeBook bookC = makeCodeBook(wC, 2, 12, true);\n\n        startTime = chrono::steady_clock::now();\n        double TL = 2.90;\n\n        SAState st;\n\n        // Phase A\n        st.init(mat, bookA);\n        anneal(st, 0.0, 0.95, 4000.0, 40.0,\n               /*pSeg*/0.10, /*pImpose*/0.0, /*segMinK*/4, /*segMaxK*/8, /*allowImpose*/false);\n\n        // Phase B\n        st.init(mat, bookB);\n        anneal(st, 0.95, 2.40, 2500.0, 15.0,\n               /*pSeg*/0.14, /*pImpose*/0.0, /*segMinK*/5, /*segMaxK*/12, /*allowImpose*/false);\n\n        // Phase C (true objective)\n        st.init(mat, bookC);\n        array<array<uint8_t, N>, N> bestMat = mat;\n        long long bestScore = st.score;\n\n        // a bit of SA with stronger impose/segment\n        while (elapsedSec() < TL - 0.20) {\n            double now = elapsedSec();\n            double rem = (TL - 0.20) - now;\n            if (rem <= 0) break;\n            double tStart = now;\n            double tEnd = now + min(0.20, rem);\n\n            anneal(st, tStart, tEnd, 80.0, 0.8,\n                   /*pSeg*/0.10, /*pImpose*/0.14, /*segMinK*/6, /*segMaxK*/12, /*allowImpose*/true);\n\n            if (st.score > bestScore) {\n                bestScore = st.score;\n                bestMat = mat;\n            }\n        }\n        mat = bestMat;\n        st.init(mat, bookC);\n\n        // Greedy finishing\n        greedyFinishFull(st, TL - 0.05);\n\n        // If perfect, try to introduce '.' safely\n        pruneDotsIfAllCovered(bookC);\n\n        // Output\n        for (int i = 0; i < N; i++) {\n            string out;\n            out.reserve(N);\n            for (int j = 0; j < N; j++) {\n                uint8_t v = mat[i][j];\n                if (v == DOT) out.push_back('.');\n                else out.push_back(char('A' + v));\n            }\n            cout << out << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, M;\n    cin >> n >> M;\n\n    Solver solver(M);\n    solver.inputs.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        string s;\n        cin >> s;\n        vector<uint8_t> v;\n        v.reserve(s.size());\n        for (char c : s) v.push_back((uint8_t)(c - 'A')); // 'A'..'H' -> 0..7\n        solver.inputs.push_back(std::move(v));\n    }\n\n    solver.solveAndPrint();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed=88172645463325252ULL) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    uint64_t operator()() { return next(); }\n    int next_int(int lo, int hi) { return lo + (int)(next() % (uint64_t)(hi - lo + 1)); }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj;\n    vector<int> dist;\n    vector<int> pairU, pairV;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    void add_edge(int u, int v) { adj[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                int u2 = pairV[v];\n                if(u2 != -1 && dist[u2] == -1){\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n                if(u2 == -1) found = true;\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for(int v: adj[u]){\n            int u2 = pairV[v];\n            if(u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))){\n                pairU[u] = v;\n                pairV[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        pairU.assign(nL, -1);\n        pairV.assign(nR, -1);\n        int matching = 0;\n        while(bfs()){\n            for(int u=0; u<nL; u++){\n                if(pairU[u] == -1 && dfs(u)) matching++;\n            }\n        }\n        return matching;\n    }\n\n    // After max_matching(), returns min vertex cover as (coverL, coverR)\n    // Standard: BFS from unmatched L using alternating paths (non-matching L->R, matching R->L).\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                if(pairU[u] == v) continue; // only non-matching edges L->R\n                if(!visR[v]){\n                    visR[v] = 1;\n                    int u2 = pairV[v]; // matching edge R->L\n                    if(u2 != -1 && !visL[u2]){\n                        visL[u2] = 1;\n                        q.push(u2);\n                    }\n                }\n            }\n        }\n        // min vertex cover: (L \\ Z) \u222a (R \u2229 Z)\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for(int u=0; u<nL; u++) if(!visL[u]) coverL[u] = 1;\n        for(int v=0; v<nR; v++) if(visR[v])  coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct Solver {\n    int N, si, sj;\n    vector<string> c;\n\n    vector<vector<int>> id; // -1 for obstacle\n    vector<int> xs, ys, w;  // per node\n    int R = 0;\n\n    vector<int> hseg, vseg;\n    int H = 0, V = 0;\n\n    // Visibility bitsets (for final relaxation / safety)\n    int W64 = 0;\n    vector<uint64_t> hbits, vbits;\n    vector<uint64_t> visFlat;\n    vector<uint64_t> allMask;\n\n    // Dijkstra buffers\n    static constexpr long long INF = (1LL<<60);\n    vector<long long> dist;\n    vector<int> prevv;\n\n    inline bool inb(int x,int y) const { return 0<=x && x<N && 0<=y && y<N; }\n\n    void read() {\n        cin >> N >> si >> sj;\n        c.resize(N);\n        for(int i=0;i<N;i++) cin >> c[i];\n    }\n\n    void build_nodes() {\n        id.assign(N, vector<int>(N, -1));\n        xs.clear(); ys.clear(); w.clear();\n        R = 0;\n        for(int i=0;i<N;i++){\n            for(int j=0;j<N;j++){\n                if(c[i][j] == '#') continue;\n                id[i][j] = R++;\n                xs.push_back(i);\n                ys.push_back(j);\n                w.push_back(c[i][j]-'0');\n            }\n        }\n        dist.assign(R, INF);\n        prevv.assign(R, -1);\n        hseg.assign(R, -1);\n        vseg.assign(R, -1);\n    }\n\n    void build_segments() {\n        H = 0;\n        for(int i=0;i<N;i++){\n            int j=0;\n            while(j<N){\n                if(id[i][j] == -1){ j++; continue; }\n                int sid = H++;\n                while(j<N && id[i][j] != -1){\n                    hseg[id[i][j]] = sid;\n                    j++;\n                }\n            }\n        }\n        V = 0;\n        for(int j=0;j<N;j++){\n            int i=0;\n            while(i<N){\n                if(id[i][j] == -1){ i++; continue; }\n                int sid = V++;\n                while(i<N && id[i][j] != -1){\n                    vseg[id[i][j]] = sid;\n                    i++;\n                }\n            }\n        }\n    }\n\n    void build_visibility_bitsets() {\n        W64 = (R + 63) / 64;\n        hbits.assign((size_t)H * W64, 0ULL);\n        vbits.assign((size_t)V * W64, 0ULL);\n        visFlat.assign((size_t)R * W64, 0ULL);\n\n        for(int v=0; v<R; v++){\n            int hi=hseg[v], vi=vseg[v];\n            int word=v>>6, bit=v&63;\n            hbits[(size_t)hi * W64 + word] |= (1ULL<<bit);\n            vbits[(size_t)vi * W64 + word] |= (1ULL<<bit);\n        }\n        for(int v=0; v<R; v++){\n            uint64_t* dst = &visFlat[(size_t)v * W64];\n            const uint64_t* hb = &hbits[(size_t)hseg[v] * W64];\n            const uint64_t* vb = &vbits[(size_t)vseg[v] * W64];\n            for(int k=0;k<W64;k++) dst[k] = hb[k] | vb[k];\n        }\n\n        allMask.assign(W64, ~0ULL);\n        if(R % 64 != 0) allMask[W64-1] = (1ULL << (R%64)) - 1ULL;\n    }\n\n    inline void for_neighbors(int v, const function<void(int)>& f) const {\n        int x=xs[v], y=ys[v];\n        if(x>0){ int u=id[x-1][y]; if(u!=-1) f(u); }\n        if(x+1<N){ int u=id[x+1][y]; if(u!=-1) f(u); }\n        if(y>0){ int u=id[x][y-1]; if(u!=-1) f(u); }\n        if(y+1<N){ int u=id[x][y+1]; if(u!=-1) f(u); }\n    }\n\n    template<class Pred>\n    int dijkstra_until(int s, Pred pred) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            if(pred(v)) return v;\n            for_neighbors(v, [&](int to){\n                long long nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push({nd,to});\n                }\n            });\n        }\n        return -1;\n    }\n\n    void dijkstra_all(int s) {\n        fill(dist.begin(), dist.end(), INF);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            for_neighbors(v, [&](int to){\n                long long nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.push({nd,to});\n                }\n            });\n        }\n    }\n\n    vector<int> restore_path(int s, int t) {\n        vector<int> path;\n        int cur = t;\n        while(cur != -1){\n            path.push_back(cur);\n            if(cur == s) break;\n            cur = prevv[cur];\n        }\n        reverse(path.begin(), path.end());\n        if(path.empty() || path.front() != s) return {s}; // safety fallback\n        return path;\n    }\n\n    long long route_time(const vector<int>& route) const {\n        long long t=0;\n        for(size_t i=1;i<route.size();i++) t += w[route[i]];\n        return t;\n    }\n\n    struct Required {\n        vector<char> needH, needV;\n        int total = 0;\n    };\n\n    Required compute_required_by_min_vertex_cover() {\n        // Build bipartite graph edges (H -> V) using all cells (edges).\n        vector<vector<int>> adj(H);\n        for(int v=0; v<R; v++){\n            adj[hseg[v]].push_back(vseg[v]);\n        }\n        for(int u=0; u<H; u++){\n            auto &vec = adj[u];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n        }\n\n        HopcroftKarp hk(H, V);\n        hk.adj = std::move(adj);\n        hk.max_matching();\n        auto [coverL, coverR] = hk.min_vertex_cover();\n\n        Required req;\n        req.needH = std::move(coverL);\n        req.needV = std::move(coverR);\n        req.total = 0;\n        for(char x: req.needH) req.total += (x!=0);\n        for(char x: req.needV) req.total += (x!=0);\n\n        // Safety: if something goes wrong (shouldn't), fall back to all horizontals.\n        if(req.total == 0){\n            req.needH.assign(H, 1);\n            req.needV.assign(V, 0);\n            req.total = H;\n        }\n        return req;\n    }\n\n    // Build a greedy route that covers all required segments; also outputs the \"stop nodes\" (waypoints)\n    vector<int> build_greedy_route_required(int startId, const Required& req, vector<int>& stops) {\n        vector<char> coveredH(H, 0), coveredV(V, 0);\n        int rem = req.total;\n\n        auto cover_node = [&](int v){\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi] && !coveredH[hi]){ coveredH[hi]=1; rem--; }\n            if(req.needV[vi] && !coveredV[vi]){ coveredV[vi]=1; rem--; }\n        };\n\n        vector<int> route;\n        route.push_back(startId);\n        cover_node(startId);\n\n        stops.clear();\n        stops.push_back(startId);\n\n        int cur = startId;\n        while(rem > 0){\n            int target = dijkstra_until(cur, [&](int v){\n                int hi=hseg[v], vi=vseg[v];\n                return (req.needH[hi] && !coveredH[hi]) || (req.needV[vi] && !coveredV[vi]);\n            });\n            if(target == -1) break; // should not happen\n\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++){\n                route.push_back(path[i]);\n                cover_node(path[i]);\n            }\n            cur = target;\n            stops.push_back(cur);\n        }\n\n        // return to start\n        if(cur != startId){\n            int target = dijkstra_until(cur, [&](int v){ return v == startId; });\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++) route.push_back(path[i]);\n        }\n\n        // avoid t=0\n        if(route.size() == 1 && R > 1){\n            int nb = -1;\n            for_neighbors(startId, [&](int to){ if(nb==-1) nb=to; });\n            if(nb != -1){\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n        }\n        return route;\n    }\n\n    // Remove redundant stops while preserving required coverage (stop covers at most two required segments).\n    void prune_redundant_stops(vector<int>& stops, const Required& req) {\n        if(stops.size() <= 1) return;\n        // Remove consecutive duplicates\n        {\n            vector<int> tmp;\n            tmp.reserve(stops.size());\n            for(int v: stops){\n                if(tmp.empty() || tmp.back() != v) tmp.push_back(v);\n            }\n            stops.swap(tmp);\n        }\n\n        vector<int> cntH(H, 0), cntV(V, 0);\n        auto add = [&](int v, int delta){\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi]) cntH[hi] += delta;\n            if(req.needV[vi]) cntV[vi] += delta;\n        };\n        for(int v: stops) add(v, +1);\n\n        vector<char> keep(stops.size(), 1);\n        keep[0] = 1; // keep start\n\n        // Try removing in reverse (often helps)\n        for(int i=(int)stops.size()-1; i>=1; i--){\n            int v = stops[i];\n            int hi=hseg[v], vi=vseg[v];\n            bool ok = true;\n            if(req.needH[hi] && cntH[hi] <= 1) ok = false;\n            if(req.needV[vi] && cntV[vi] <= 1) ok = false;\n            if(ok){\n                keep[i] = 0;\n                add(v, -1);\n            }\n        }\n        vector<int> out;\n        out.reserve(stops.size());\n        for(size_t i=0;i<stops.size();i++) if(keep[i]) out.push_back(stops[i]);\n        stops.swap(out);\n    }\n\n    // Build all-pairs shortest path distances between waypoints (directed).\n    vector<vector<int>> build_waypoint_dist(const vector<int>& wp) {\n        int m = (int)wp.size();\n        vector<vector<int>> D(m, vector<int>(m, INT_MAX/4));\n        for(int i=0;i<m;i++){\n            dijkstra_all(wp[i]);\n            for(int j=0;j<m;j++){\n                long long d = dist[wp[j]];\n                if(d >= INF/2) D[i][j] = INT_MAX/4;\n                else D[i][j] = (int)d;\n            }\n        }\n        return D;\n    }\n\n    long long cycle_cost(const vector<int>& seq, const vector<vector<int>>& D) {\n        int m = (int)seq.size();\n        long long cost = 0;\n        for(int i=0;i<m;i++){\n            int a = seq[i];\n            int b = seq[(i+1)%m];\n            cost += D[a][b];\n        }\n        return cost;\n    }\n\n    // Hillclimb on a directed cycle with fixed start at pos 0.\n    // seq contains indices into wp (not node ids). seq[0] must be 0.\n    void optimize_waypoint_order(vector<int>& seq, const vector<vector<int>>& D, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        int m = (int)seq.size();\n        if(m <= 3) return;\n\n        auto prev_idx = [&](int i){ return (i-1+m)%m; };\n        auto next_idx = [&](int i){ return (i+1)%m; };\n\n        long long best = cycle_cost(seq, D);\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            uint64_t r = rng();\n            if((r & 1ULL) == 0ULL){\n                // Relocate (insertion)\n                int i = 1 + (int)(rng() % (uint64_t)(m-1)); // move this\n                int j = (int)(rng() % (uint64_t)m);        // insert after this\n                if(j == i) continue;\n                if(next_idx(j) == i) continue; // no-op\n\n                int pi = prev_idx(i), ni = next_idx(i);\n                int a = seq[pi], x = seq[i], b = seq[ni];\n                int c = seq[j], d = seq[next_idx(j)];\n\n                long long old = (long long)D[a][x] + D[x][b] + D[c][d];\n                long long neu = (long long)D[a][b] + D[c][x] + D[x][d];\n                long long delta = neu - old;\n                if(delta >= 0) continue;\n\n                // apply relocate in seq (on linear vector, careful with indices)\n                int xval = seq[i];\n                if(i < j){\n                    seq.erase(seq.begin() + i);\n                    seq.insert(seq.begin() + j, xval); // after erase, j shifts left by 1, inserting at j places x before old seq[j+1], which is after old j\n                }else{\n                    seq.erase(seq.begin() + i);\n                    seq.insert(seq.begin() + j + 1, xval);\n                }\n                // ensure start fixed\n                if(seq[0] != 0){\n                    // rotate back so that 0 at front (shouldn't happen because we never move 0)\n                    auto it = find(seq.begin(), seq.end(), 0);\n                    rotate(seq.begin(), it, seq.end());\n                }\n                best += delta;\n            }else{\n                // Swap\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = 1 + (int)(rng() % (uint64_t)(m-1));\n                if(i == j) continue;\n                if(i > j) swap(i,j);\n\n                int pi = prev_idx(i), ni = next_idx(i);\n                int pj = prev_idx(j), nj = next_idx(j);\n\n                int a = seq[pi], b = seq[i], c = seq[ni];\n                int d = seq[pj], e = seq[j], f = seq[nj];\n\n                long long old, neu;\n                if(ni == j){ // adjacent i -> j\n                    old = (long long)D[a][b] + D[b][e] + D[e][f];\n                    neu = (long long)D[a][e] + D[e][b] + D[b][f];\n                }else{\n                    old = (long long)D[a][b] + D[b][c] + D[d][e] + D[e][f];\n                    neu = (long long)D[a][e] + D[e][c] + D[d][b] + D[b][f];\n                }\n                long long delta = neu - old;\n                if(delta >= 0) continue;\n\n                swap(seq[i], seq[j]);\n                best += delta;\n            }\n        }\n    }\n\n    vector<int> build_route_from_waypoints(const vector<int>& wpNodesInOrder) {\n        int m = (int)wpNodesInOrder.size();\n        vector<int> route;\n        route.push_back(wpNodesInOrder[0]);\n\n        for(int i=0;i<m;i++){\n            int s = wpNodesInOrder[i];\n            int t = wpNodesInOrder[(i+1)%m];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            (void)reached;\n            auto path = restore_path(s, t);\n            for(size_t k=1;k<path.size();k++) route.push_back(path[k]);\n        }\n\n        // avoid t=0\n        if(route.size() == 1 && R > 1){\n            int startId = route[0];\n            int nb=-1;\n            for_neighbors(startId, [&](int to){ if(nb==-1) nb=to; });\n            if(nb!=-1){\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n        }\n        return route;\n    }\n\n    pair<bool,long long> eval_required(const vector<int>& route, const Required& req) const {\n        vector<char> seenH(H, 0), seenV(V, 0);\n        int rem = req.total;\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi] && !seenH[hi]){ seenH[hi]=1; rem--; }\n            if(req.needV[vi] && !seenV[vi]){ seenV[vi]=1; rem--; }\n        }\n        return {rem==0, t};\n    }\n\n    pair<bool,long long> eval_full_visibility(const vector<int>& route) const {\n        vector<uint64_t> cov(W64, 0ULL);\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            const uint64_t* vb = &visFlat[(size_t)v * W64];\n            for(int k=0;k<W64;k++) cov[k] |= vb[k];\n        }\n        for(int k=0;k<W64;k++){\n            if(cov[k] != allMask[k]) return {false, t};\n        }\n        return {true, t};\n    }\n\n    vector<int> improve_by_shortcuts_required(vector<int> route, const Required& req, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_required(route, req);\n        (void)ok0;\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 10) continue;\n\n            int len = 5 + (int)(rng() % 220);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin() + a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_required(nr, req);\n            if(ok && newT < bestT){\n                route.swap(nr);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    vector<int> improve_by_shortcuts_full(vector<int> route, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_full_visibility(route);\n        if(!ok0) return route;\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 10) continue;\n\n            int len = 5 + (int)(rng() % 180);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin() + a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_full_visibility(nr);\n            if(ok && newT < bestT){\n                route.swap(nr);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    string route_to_moves(const vector<int>& route) const {\n        string out;\n        out.reserve(route.size() ? route.size()-1 : 0);\n        for(size_t i=1;i<route.size();i++){\n            int a=route[i-1], b=route[i];\n            int x1=xs[a], y1=ys[a], x2=xs[b], y2=ys[b];\n            if(x2==x1-1 && y2==y1) out.push_back('U');\n            else if(x2==x1+1 && y2==y1) out.push_back('D');\n            else if(x2==x1 && y2==y1-1) out.push_back('L');\n            else if(x2==x1 && y2==y1+1) out.push_back('R');\n            else {\n                // Should never happen\n            }\n        }\n        return out;\n    }\n\n    void solve() {\n        read();\n        build_nodes();\n        build_segments();\n        build_visibility_bitsets();\n\n        int startId = id[si][sj];\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        auto globalSt = chrono::steady_clock::now();\n\n        // 1) Compute required segments via minimum vertex cover\n        Required req = compute_required_by_min_vertex_cover();\n\n        // 2) Greedy covering route + stops\n        vector<int> stops;\n        vector<int> route0 = build_greedy_route_required(startId, req, stops);\n\n        // 3) Prune redundant stops\n        prune_redundant_stops(stops, req);\n\n        // 4) Directed TSP-like improvement on stops using all-pairs distances\n        // Build waypoint list (node ids) and index-cycle (indices into wp)\n        vector<int> wp = stops; // node ids, wp[0] is start\n        int m = (int)wp.size();\n        if(m >= 2){\n            // Build distance matrix between waypoint indices\n            auto D = build_waypoint_dist(wp);\n\n            vector<int> seq(m);\n            iota(seq.begin(), seq.end(), 0); // start with current order\n            // optimize time budget based on remaining\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n            double budget = max(0.2, 1.0 - elapsed);\n            optimize_waypoint_order(seq, D, budget, rng);\n\n            // Convert optimized seq of indices into node ids in that order\n            vector<int> wpOrder;\n            wpOrder.reserve(m);\n            for(int idx: seq) wpOrder.push_back(wp[idx]);\n\n            // Rebuild route from optimized waypoints\n            route0 = build_route_from_waypoints(wpOrder);\n        }\n\n        // 5) Shortcut improvement while preserving required segments\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n        double remain = 2.85 - elapsed;\n        if(remain > 0.10){\n            double t1 = min(0.9, remain * 0.55);\n            route0 = improve_by_shortcuts_required(std::move(route0), req, t1, rng);\n        }\n\n        // 6) Final relaxation: allow changing the implicit cover, only enforce full visibility\n        elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n        remain = 2.90 - elapsed;\n        if(remain > 0.08){\n            route0 = improve_by_shortcuts_full(std::move(route0), remain, rng);\n        }\n\n        cout << route_to_moves(route0) << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver s;\n    s.solve();\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MaxPairCmp {\n    bool operator()(const pair<long long,int>& a, const pair<long long,int>& b) const {\n        return a.first < b.first; // max-heap\n    }\n};\n\nstatic inline double clampd(double x, double lo, double hi){\n    if(x < lo) return lo;\n    if(x > hi) return hi;\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N,M,K,R;\n    cin >> N >> M >> K >> R;\n\n    vector<vector<int>> d(N, vector<int>(K));\n    for(int i=0;i<N;i++){\n        for(int k=0;k<K;k++) cin >> d[i][k];\n    }\n\n    vector<vector<int>> g(N);\n    vector<int> indeg(N,0), outdeg(N,0);\n    for(int i=0;i<R;i++){\n        int u,v; cin >> u >> v;\n        --u; --v;\n        g[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    // critical path length (works by index because u < v)\n    vector<int> cp(N,1);\n    for(int i=N-1;i>=0;i--){\n        int best=1;\n        for(int v: g[i]) best = max(best, 1 + cp[v]);\n        cp[i]=best;\n    }\n\n    vector<int> diff(N,0);\n    for(int i=0;i<N;i++){\n        int s=0;\n        for(int k=0;k<K;k++) s += d[i][k];\n        diff[i]=s;\n    }\n\n    // base static key for extracting high-priority tasks\n    vector<long long> baseKey(N);\n    for(int i=0;i<N;i++){\n        baseKey[i] = (long long)cp[i]*1'000'000LL\n                   + (long long)diff[i]*1'000LL\n                   + (long long)outdeg[i]*10LL\n                   - (long long)i;\n    }\n\n    // state: 0 not started, 1 in progress, 2 done\n    vector<int> state(N,0);\n\n    // Ready management\n    vector<char> in_ready(N, 0);\n    vector<int> ready_since(N, 0);\n\n    // Two PQs: by priority and by age (oldest first)\n    priority_queue<pair<long long,int>, vector<pair<long long,int>>, MaxPairCmp> pq_key;\n    priority_queue<pair<long long,int>, vector<pair<long long,int>>, MaxPairCmp> pq_age;\n\n    auto push_ready = [&](int task, int day){\n        if(in_ready[task]) return;\n        if(state[task] != 0) return;\n        if(indeg[task] != 0) return;\n        in_ready[task] = 1;\n        // day when it became ready (end of that day). initial tasks use 0.\n        // use negative for age ordering: older (smaller ready_since) -> larger key\n        pq_key.push({baseKey[task], task});\n        pq_age.push({-(long long)ready_since[task], task});\n    };\n\n    // initialize ready tasks\n    for(int i=0;i<N;i++){\n        if(indeg[i]==0){\n            ready_since[i]=0;\n            push_ready(i, 0);\n        }\n    }\n\n    // Member/task status\n    vector<int> member_task(M, -1);\n    vector<int> member_start(M, -1);\n\n    // Skill estimates\n    const double SKILL_INIT = 10.0;\n    const double SKILL_MIN = 0.0;\n    const double SKILL_MAX = 80.0;\n    vector<vector<double>> shat(M, vector<double>(K, SKILL_INIT));\n    vector<int> samples(M, 0);\n\n    auto predict_w = [&](int task, int mem)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double def = (double)d[task][k] - shat[mem][k];\n            if(def > 0) w += def;\n        }\n        return w;\n    };\n\n    auto predict_time = [&](int task, int mem)->double{\n        // Conservative bias + uncertainty for low samples\n        double w = predict_w(task, mem);\n        double uncert = 1.5 / sqrt(1.0 + samples[mem]);\n        double bias = 0.6; // mild safety buffer\n        return max(1.0, w + bias + uncert);\n    };\n\n    auto update_skill_interval = [&](int mem, int task, int t_obs){\n        // Convert observed duration to an interval for w, considering r_i in [-3,3].\n        // Also note that when w>0, t can still be 1, so t==1 only gives w<=4.\n        double lo, hi;\n        if(t_obs <= 1){\n            lo = 0.0;\n            hi = 4.0;\n        }else{\n            lo = max(1.0, (double)t_obs - 3.0);\n            hi = (double)t_obs + 3.0;\n        }\n\n        vector<double> def(K);\n        vector<int> active;\n        active.reserve(K);\n        double w_hat=0.0;\n\n        for(int k=0;k<K;k++){\n            def[k] = max(0.0, (double)d[task][k] - shat[mem][k]);\n            if(def[k] > 1e-12) active.push_back(k);\n            w_hat += def[k];\n        }\n\n        if(lo - 1e-9 <= w_hat && w_hat <= hi + 1e-9) return;\n\n        double lr = 0.8 / sqrt(1.0 + samples[mem]); // decreasing step size\n\n        if(w_hat > hi){\n            // Need to reduce w -> increase skills on active dimensions.\n            double delta_total = w_hat - hi;\n            double step = lr * delta_total;\n\n            if(active.empty()) return; // w_hat=0 can't be >hi\n            // distribute proportionally to current deficits\n            for(int k: active){\n                double frac = def[k] / w_hat;\n                double inc = step * frac;\n                // can't remove more deficit than exists (cap at def[k])\n                inc = min(inc, def[k]);\n                shat[mem][k] = clampd(shat[mem][k] + inc, SKILL_MIN, SKILL_MAX);\n            }\n        }else{ // w_hat < lo\n            // Need to increase w -> decrease skills.\n            double delta_total = lo - w_hat;\n            double step = lr * delta_total;\n\n            if(!active.empty()){\n                // easiest: decrease already-active dims (increases w 1-to-1)\n                double wsum = 0.0;\n                for(int k: active) wsum += (def[k] + 1.0); // avoid too peaky when def small\n                for(int k: active){\n                    double frac = (def[k] + 1.0) / wsum;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }else{\n                // predicted w==0 but observation suggests w>=1: lower some skills to create deficit.\n                // distribute by task requirements.\n                double sumd = 1e-9;\n                for(int k=0;k<K;k++) sumd += d[task][k] + 1.0;\n                for(int k=0;k<K;k++){\n                    double frac = (d[task][k] + 1.0) / sumd;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }\n        }\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const int CKEY = 180;\n    const int CAGE = 80;\n\n    for(int day=1; day<=2000; day++){\n        // free members\n        vector<int> free_m;\n        free_m.reserve(M);\n        for(int j=0;j<M;j++) if(member_task[j]==-1) free_m.push_back(j);\n        shuffle(free_m.begin(), free_m.end(), rng);\n\n        // collect candidate tasks from pq_key and pq_age\n        vector<int> cand;\n        cand.reserve(CKEY + CAGE + 20);\n        vector<char> in_cand(N, 0);\n\n        vector<pair<long long,int>> popped_key, popped_age;\n        popped_key.reserve(CKEY*2);\n        popped_age.reserve(CAGE*2);\n\n        auto collect_from = [&](auto &pq, int C, vector<pair<long long,int>> &popped){\n            while(!pq.empty() && (int)cand.size() < CKEY + CAGE){\n                auto top = pq.top(); pq.pop();\n                popped.push_back(top);\n                int t = top.second;\n                if(state[t]!=0) continue;\n                if(indeg[t]!=0) continue;\n                if(!in_ready[t]) continue;\n                if(in_cand[t]) continue;\n                in_cand[t]=1;\n                cand.push_back(t);\n                if((int)cand.size() >= C) break;\n            }\n        };\n\n        collect_from(pq_key, CKEY, popped_key);\n        collect_from(pq_age, CKEY + CAGE, popped_age); // total bound via cand size\n\n        // If no candidates or no free members -> output 0\n        vector<pair<int,int>> assigns;\n\n        if(!free_m.empty() && !cand.empty()){\n            struct PairScore{\n                double s;\n                int mem;\n                int task;\n            };\n            vector<PairScore> pairs;\n            pairs.reserve((int)free_m.size() * (int)cand.size());\n\n            for(int mem: free_m){\n                for(int task: cand){\n                    double pt = predict_time(task, mem);\n\n                    // Task priority component\n                    double pr = (double)cp[task]\n                              + 0.03 * (double)outdeg[task]\n                              + 0.001 * (double)diff[task];\n\n                    // age bonus to avoid long tail\n                    double age = (double)(day - ready_since[task]);\n                    double age_bonus = 0.0008 * age;\n\n                    // exploration bonus for less-sampled members\n                    double explore_bonus = 0.02 / sqrt(1.0 + samples[mem]);\n\n                    // final desirability: critical tasks, fast member fit\n                    double score = pr / pow(pt, 0.85) + age_bonus + explore_bonus;\n                    pairs.push_back({score, mem, task});\n                }\n            }\n\n            sort(pairs.begin(), pairs.end(), [&](const PairScore& a, const PairScore& b){\n                return a.s > b.s;\n            });\n\n            vector<char> used_mem(M, 0), used_task(N, 0);\n            for(auto &p: pairs){\n                if(used_mem[p.mem]) continue;\n                if(used_task[p.task]) continue;\n                // assign\n                used_mem[p.mem] = 1;\n                used_task[p.task] = 1;\n                assigns.push_back({p.mem, p.task});\n\n                state[p.task] = 1;\n                member_task[p.mem] = p.task;\n                member_start[p.mem] = day;\n                in_ready[p.task] = 0;\n\n                if((int)assigns.size() == (int)free_m.size()) break;\n            }\n        }\n\n        // re-push popped PQ entries if still relevant and not assigned today\n        vector<char> assigned_today(N, 0);\n        for(auto [m,t]: assigns) assigned_today[t] = 1;\n\n        for(auto &e: popped_key){\n            int t = e.second;\n            if(state[t]==0 && indeg[t]==0 && in_ready[t] && !assigned_today[t]){\n                pq_key.push(e);\n            }\n        }\n        for(auto &e: popped_age){\n            int t = e.second;\n            if(state[t]==0 && indeg[t]==0 && in_ready[t] && !assigned_today[t]){\n                pq_age.push(e);\n            }\n        }\n\n        // output assignments\n        cout << assigns.size();\n        for(auto [mem, task]: assigns){\n            cout << ' ' << (mem+1) << ' ' << (task+1);\n        }\n        cout << '\\n' << flush;\n\n        // input finished members\n        int nfin;\n        cin >> nfin;\n        if(nfin == -1) return 0;\n\n        for(int i=0;i<nfin;i++){\n            int f; cin >> f; --f;\n            int task = member_task[f];\n            int st = member_start[f];\n            int t_obs = day - st + 1;\n\n            update_skill_interval(f, task, t_obs);\n            samples[f]++;\n\n            member_task[f] = -1;\n            member_start[f] = -1;\n\n            state[task] = 2;\n\n            for(int v: g[task]){\n                indeg[v]--;\n                if(indeg[v]==0 && state[v]==0){\n                    ready_since[v] = day; // became ready at end of this day\n                    push_ready(v, day);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Order { int ax, ay, cx, cy; };\nstruct Point { int x, y; };\nstatic inline int distMan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\nstatic const Point OFFICE{400, 400};\n\nstruct Node {\n    int id;      // 0..999\n    uint8_t tp;  // 0 pickup, 1 delivery\n};\n\nstruct RNG {\n    uint64_t s;\n    explicit RNG(uint64_t seed) : s(seed) {}\n    static inline uint64_t splitmix64(uint64_t &x) {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    inline uint64_t next_u64() { return splitmix64(s); }\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct BestState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    int cost = INT_MAX;\n};\n\nstruct CurState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    array<Point,102> pts{}; // OFFICE + 100 nodes + OFFICE\n    int cost = INT_MAX;\n\n    array<int,1000> pickPos;\n    array<int,1000> delPos;\n    array<uint8_t,1000> selected;\n};\n\nstatic inline Point nodePoint(const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              const Node& nd) {\n    return (nd.tp == 0 ? pickPt[nd.id] : delPt[nd.id]);\n}\n\nstatic inline int computeCostFromPts(const array<Point,102>& pts) {\n    int c = 0;\n    for (int i = 0; i < 101; i++) c += distMan(pts[i], pts[i+1]);\n    return c;\n}\n\nstatic void buildPtsAndPos(CurState& st,\n                           const array<Point,1000>& pickPt,\n                           const array<Point,1000>& delPt) {\n    st.pts[0] = OFFICE;\n    for (int i = 0; i < 100; i++) st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[101] = OFFICE;\n    st.cost = computeCostFromPts(st.pts);\n\n    st.pickPos.fill(-1);\n    st.delPos.fill(-1);\n    for (int i = 0; i < 100; i++) {\n        const Node &nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n}\n\nstatic array<Node,100> buildGreedyInterleaving(const array<Point,1000>& pickPt,\n                                               const array<Point,1000>& delPt,\n                                               const array<int,50>& sel) {\n    vector<int> unpicked; unpicked.reserve(50);\n    for (int i = 0; i < 50; i++) unpicked.push_back(sel[i]);\n    vector<int> carrying; carrying.reserve(50);\n\n    array<Node,100> seq;\n    Point cur = OFFICE;\n\n    auto erase_by_swap_back = [](vector<int>& v, int idx) {\n        v[idx] = v.back();\n        v.pop_back();\n    };\n\n    for (int t = 0; t < 100; t++) {\n        int bestDist = INT_MAX;\n        int bestId = -1;\n        int bestType = -1; // 0 pickup, 1 delivery\n        int bestIdx = -1;\n\n        for (int i = 0; i < (int)unpicked.size(); i++) {\n            int id = unpicked[i];\n            int d = distMan(cur, pickPt[id]);\n            if (d < bestDist) {\n                bestDist = d;\n                bestId = id;\n                bestType = 0;\n                bestIdx = i;\n            }\n        }\n        for (int i = 0; i < (int)carrying.size(); i++) {\n            int id = carrying[i];\n            int d = distMan(cur, delPt[id]);\n            if (d < bestDist) {\n                bestDist = d;\n                bestId = id;\n                bestType = 1;\n                bestIdx = i;\n            }\n        }\n\n        if (bestType == 0) {\n            seq[t] = Node{bestId, 0};\n            cur = pickPt[bestId];\n            carrying.push_back(bestId);\n            erase_by_swap_back(unpicked, bestIdx);\n        } else {\n            seq[t] = Node{bestId, 1};\n            cur = delPt[bestId];\n            erase_by_swap_back(carrying, bestIdx);\n        }\n    }\n    return seq;\n}\n\nstatic inline void applyRelocate(array<Node,100>& a, int i, int j) {\n    if (i == j) return;\n    Node tmp = a[i];\n    if (i < j) {\n        for (int k = i; k < j; k++) a[k] = a[k+1];\n        a[j] = tmp;\n    } else {\n        for (int k = i; k > j; k--) a[k] = a[k-1];\n        a[j] = tmp;\n    }\n}\n\nstatic inline int deltaSwapPts(const array<Point,102>& pts, int i, int j) {\n    int a = i + 1;\n    int b = j + 1;\n\n    auto getPt = [&](int idx)->Point {\n        if (idx == a) return pts[b];\n        if (idx == b) return pts[a];\n        return pts[idx];\n    };\n\n    int edges[4] = {a-1, a, b-1, b};\n    sort(edges, edges+4);\n    int oldc = 0, newc = 0;\n    int last = -999;\n    for (int k = 0; k < 4; k++) {\n        int e = edges[k];\n        if (e == last) continue;\n        last = e;\n        if (0 <= e && e <= 100) {\n            oldc += distMan(pts[e], pts[e+1]);\n            newc += distMan(getPt(e), getPt(e+1));\n        }\n    }\n    return newc - oldc;\n}\n\nstatic inline int deltaRelocatePts(const array<Point,102>& pts, int i, int j) {\n    // Move node at i to j (final index), using original pts for delta computation\n    const Point& X = pts[i+1];\n    const Point& A = pts[i];\n    const Point& B = pts[i+2];\n    int delta_rem = distMan(A, B) - distMan(A, X) - distMan(X, B);\n\n    Point C, D;\n    if (i < j) {\n        C = pts[j+1];\n        D = pts[j+2];\n    } else {\n        C = pts[j];\n        D = pts[j+1];\n    }\n    int delta_ins = distMan(C, X) + distMan(X, D) - distMan(C, D);\n    return delta_rem + delta_ins;\n}\n\nstatic inline bool canRelocateOrderConstraint(const CurState& st, int i, int j) {\n    const Node& nd = st.seq[i];\n    int id = nd.id;\n    int p = st.pickPos[id];\n    int d = st.delPos[id];\n    int other = (nd.tp == 0 ? d : p);\n\n    int new_other = other;\n    if (i < j) {\n        if (other >= i + 1 && other <= j) new_other = other - 1;\n    } else { // i > j\n        if (other >= j && other <= i - 1) new_other = other + 1;\n    }\n\n    if (nd.tp == 0) {\n        // pickup moves to j\n        return j < new_other;\n    } else {\n        // delivery moves to j\n        return new_other < j;\n    }\n}\n\nstatic inline bool canSwapOrderConstraint(const CurState& st, int i, int j) {\n    const Node& a = st.seq[i];\n    const Node& b = st.seq[j];\n    if (a.id == b.id) return false;\n\n    {\n        int id = a.id;\n        int np = (a.tp == 0 ? j : st.pickPos[id]);\n        int nd = (a.tp == 1 ? j : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    {\n        int id = b.id;\n        int np = (b.tp == 0 ? i : st.pickPos[id]);\n        int nd = (b.tp == 1 ? i : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    return true;\n}\n\nstatic void updateRangeAfterRelocate(CurState& st,\n                                     const array<Point,1000>& pickPt,\n                                     const array<Point,1000>& delPt,\n                                     int l, int r) {\n    for (int k = l; k <= r; k++) {\n        st.pts[k+1] = nodePoint(pickPt, delPt, st.seq[k]);\n        const Node& nd = st.seq[k];\n        if (nd.tp == 0) st.pickPos[nd.id] = k;\n        else st.delPos[nd.id] = k;\n    }\n}\n\nstatic void updateAfterSwap(CurState& st,\n                            const array<Point,1000>& pickPt,\n                            const array<Point,1000>& delPt,\n                            int i, int j) {\n    st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[j+1] = nodePoint(pickPt, delPt, st.seq[j]);\n    {\n        const Node& nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n    {\n        const Node& nd = st.seq[j];\n        if (nd.tp == 0) st.pickPos[nd.id] = j;\n        else st.delPos[nd.id] = j;\n    }\n}\n\nstatic vector<Node> buildBaseWithoutOrder(const array<Node,100>& seq, int pi, int di) {\n    vector<Node> base;\n    base.reserve(98);\n    for (int i = 0; i < 100; i++) if (i != pi && i != di) base.push_back(seq[i]);\n    return base;\n}\n\nstatic int computeCostForNodes(const vector<Node>& nodes,\n                               const array<Point,1000>& pickPt,\n                               const array<Point,1000>& delPt) {\n    Point cur = OFFICE;\n    int c = 0;\n    for (auto &nd : nodes) {\n        Point nxt = nodePoint(pickPt, delPt, nd);\n        c += distMan(cur, nxt);\n        cur = nxt;\n    }\n    c += distMan(cur, OFFICE);\n    return c;\n}\n\nstatic pair<vector<Node>, int> bestInsertPair(const vector<Node>& base,\n                                              const Point& pick,\n                                              const Point& del,\n                                              int idToInsert,\n                                              const array<Point,1000>& pickPt,\n                                              const array<Point,1000>& delPt) {\n    int L = (int)base.size(); // 98\n    vector<Point> pts(L + 2);\n    pts[0] = OFFICE;\n    for (int i = 0; i < L; i++) pts[i+1] = nodePoint(pickPt, delPt, base[i]);\n    pts[L+1] = OFFICE;\n\n    int baseCost = 0;\n    for (int i = 0; i < L+1; i++) baseCost += distMan(pts[i], pts[i+1]);\n\n    int bestDelta = INT_MAX;\n    int bestP = 0, bestD = 1;\n\n    for (int p = 0; p <= L; p++) {\n        // insert pickup between pts[p] and pts[p+1]\n        int delta1 = distMan(pts[p], pick) + distMan(pick, pts[p+1]) - distMan(pts[p], pts[p+1]);\n\n        auto getAfterPickup = [&](int idx)->Point {\n            // point list length L+3, indices 0..L+2\n            if (idx <= p) return pts[idx];\n            if (idx == p+1) return pick;\n            return pts[idx-1];\n        };\n\n        for (int dpos = p+1; dpos <= L+1; dpos++) {\n            Point left = getAfterPickup(dpos);\n            Point right = getAfterPickup(dpos+1);\n            int delta2 = distMan(left, del) + distMan(del, right) - distMan(left, right);\n            int tot = delta1 + delta2;\n            if (tot < bestDelta) {\n                bestDelta = tot;\n                bestP = p;\n                bestD = dpos;\n            }\n        }\n    }\n\n    vector<Node> res = base;\n    res.insert(res.begin() + bestP, Node{idToInsert, 0});\n    res.insert(res.begin() + bestD, Node{idToInsert, 1}); // bestD is in indexing after pickup insertion\n    int newCost = baseCost + bestDelta;\n    return {res, newCost};\n}\n\nstatic CurState buildStateFromSel(const array<int,50>& sel,\n                                  const array<Point,1000>& pickPt,\n                                  const array<Point,1000>& delPt) {\n    CurState st;\n    st.sel = sel;\n    st.selected.fill(0);\n    for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n\n    st.seq = buildGreedyInterleaving(pickPt, delPt, st.sel);\n    buildPtsAndPos(st, pickPt, delPt);\n    return st;\n}\n\nstatic void greedyImproveRelocate(CurState& st,\n                                  const array<Point,1000>& pickPt,\n                                  const array<Point,1000>& delPt,\n                                  RNG& rng,\n                                  int iters) {\n    for (int it = 0; it < iters; it++) {\n        int i = rng.next_int(0, 99);\n        int j = rng.next_int(0, 99);\n        if (i == j) continue;\n        if (!canRelocateOrderConstraint(st, i, j)) continue;\n\n        int delta = deltaRelocatePts(st.pts, i, j);\n        if (delta >= 0) continue;\n\n        applyRelocate(st.seq, i, j);\n        int l = min(i, j), r = max(i, j);\n        updateRangeAfterRelocate(st, pickPt, delPt, l, r);\n        st.cost += delta;\n    }\n}\n\nstatic array<int,50> sampleSelBiased(const vector<int>& pool, RNG& rng, const vector<double>& cdf) {\n    array<int,50> sel;\n    array<uint8_t,1000> used{}; used.fill(0);\n\n    double sum = cdf.back();\n    for (int k = 0; k < 50; k++) {\n        while (true) {\n            double r = rng.next_double() * sum;\n            int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n            if (idx < 0) idx = 0;\n            if (idx >= (int)pool.size()) idx = (int)pool.size() - 1;\n            int id = pool[idx];\n            if (!used[id]) {\n                used[id] = 1;\n                sel[k] = id;\n                break;\n            }\n        }\n    }\n    return sel;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> ord(1000);\n    for (int i = 0; i < 1000; i++) cin >> ord[i].ax >> ord[i].ay >> ord[i].cx >> ord[i].cy;\n\n    array<Point,1000> pickPt, delPt;\n    for (int i = 0; i < 1000; i++) {\n        pickPt[i] = Point{ord[i].ax, ord[i].ay};\n        delPt[i]  = Point{ord[i].cx, ord[i].cy};\n    }\n\n    vector<pair<int,int>> solo;\n    solo.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int c = distMan(OFFICE, pickPt[i]) + distMan(pickPt[i], delPt[i]) + distMan(delPt[i], OFFICE);\n        solo.push_back({c, i});\n    }\n    sort(solo.begin(), solo.end());\n\n    int POOL = 650;\n    vector<int> pool; pool.reserve(POOL);\n    for (int i = 0; i < min(POOL, 1000); i++) pool.push_back(solo[i].second);\n\n    // Build biased CDF for sampling from pool\n    // weight ~ 1/(rank+1)^alpha\n    const double alpha = 1.25;\n    vector<double> cdf(pool.size());\n    double acc = 0.0;\n    for (int i = 0; i < (int)pool.size(); i++) {\n        double w = 1.0 / pow((double)(i + 1), alpha);\n        acc += w;\n        cdf[i] = acc;\n    }\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    RNG rng(seed);\n\n    // Multi-start initial solutions\n    CurState cur;\n    {\n        BestState initBest;\n\n        // Start 0: best 50 by solo cost\n        array<int,50> sel0;\n        for (int i = 0; i < 50; i++) sel0[i] = solo[i].second;\n\n        {\n            CurState st = buildStateFromSel(sel0, pickPt, delPt);\n            greedyImproveRelocate(st, pickPt, delPt, rng, 2500);\n            if (st.cost < initBest.cost) {\n                initBest.cost = st.cost;\n                initBest.sel = st.sel;\n                initBest.seq = st.seq;\n            }\n        }\n\n        // Additional randomized starts\n        int RESTARTS = 7;\n        for (int r = 0; r < RESTARTS; r++) {\n            auto sel = sampleSelBiased(pool, rng, cdf);\n            CurState st = buildStateFromSel(sel, pickPt, delPt);\n            greedyImproveRelocate(st, pickPt, delPt, rng, 1800);\n            if (st.cost < initBest.cost) {\n                initBest.cost = st.cost;\n                initBest.sel = st.sel;\n                initBest.seq = st.seq;\n            }\n        }\n\n        cur.sel = initBest.sel;\n        cur.seq = initBest.seq;\n        cur.selected.fill(0);\n        for (int i = 0; i < 50; i++) cur.selected[cur.sel[i]] = 1;\n        buildPtsAndPos(cur, pickPt, delPt);\n        cur.cost = initBest.cost;\n    }\n\n    BestState best;\n    best.cost = cur.cost;\n    best.sel = cur.sel;\n    best.seq = cur.seq;\n\n    // SA time limit\n    const double TL = 1.92;\n    auto t0 = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - t0).count();\n    };\n\n    // SA temps\n    const double T0 = 2000.0;\n    const double T1 = 25.0;\n\n    while (true) {\n        double e = elapsedSec();\n        if (e >= TL) break;\n        double prog = e / TL;\n        double temp = T0 * pow(T1 / T0, prog);\n\n        double r = rng.next_double();\n\n        if (r < 0.72) {\n            // node relocate\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (!canRelocateOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaRelocatePts(cur.pts, i, j);\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else accept = (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            applyRelocate(cur.seq, i, j);\n            int l = min(i, j), rr = max(i, j);\n            updateRangeAfterRelocate(cur, pickPt, delPt, l, rr);\n            cur.cost += delta;\n\n        } else if (r < 0.92) {\n            // node swap\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (i > j) swap(i, j);\n            if (!canSwapOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaSwapPts(cur.pts, i, j);\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else accept = (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            swap(cur.seq[i], cur.seq[j]);\n            swap(cur.pts[i+1], cur.pts[j+1]);\n            // update positions for these two nodes\n            updateAfterSwap(cur, pickPt, delPt, i, j);\n            cur.cost += delta;\n\n        } else if (r < 0.985) {\n            // order reinsert (same selection)\n            int idx = rng.next_int(0, 49);\n            int id = cur.sel[idx];\n            int pi = cur.pickPos[id];\n            int di = cur.delPos[id];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            auto base = buildBaseWithoutOrder(cur.seq, pi, di);\n            auto [newNodes, newCost] = bestInsertPair(base, pickPt[id], delPt[id], id, pickPt, delPt);\n            int delta = newCost - cur.cost;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else accept = (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n\n        } else {\n            // order swap: replace one order with another from pool\n            int outIdx = rng.next_int(0, 49);\n            int outId = cur.sel[outIdx];\n\n            int inId = -1;\n            for (int tries = 0; tries < 40; tries++) {\n                int cand = pool[rng.next_int(0, (int)pool.size() - 1)];\n                if (!cur.selected[cand]) { inId = cand; break; }\n            }\n            if (inId == -1) continue;\n\n            int pi = cur.pickPos[outId];\n            int di = cur.delPos[outId];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            auto base = buildBaseWithoutOrder(cur.seq, pi, di);\n            auto [newNodes, newCost] = bestInsertPair(base, pickPt[inId], delPt[inId], inId, pickPt, delPt);\n            int delta = newCost - cur.cost;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else accept = (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            // apply selection change\n            cur.selected[outId] = 0;\n            cur.selected[inId] = 1;\n            cur.sel[outIdx] = inId;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n        }\n\n        if (cur.cost < best.cost) {\n            best.cost = cur.cost;\n            best.sel = cur.sel;\n            best.seq = cur.seq;\n        }\n    }\n\n    // Final small greedy polish on best\n    {\n        CurState st;\n        st.sel = best.sel;\n        st.seq = best.seq;\n        st.selected.fill(0);\n        for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n        buildPtsAndPos(st, pickPt, delPt);\n\n        RNG rng2(rng.next_u64());\n        greedyImproveRelocate(st, pickPt, delPt, rng2, 6000);\n\n        if (st.cost < best.cost) {\n            best.cost = st.cost;\n            best.sel = st.sel;\n            best.seq = st.seq;\n        }\n    }\n\n    // Output\n    cout << 50;\n    for (int i = 0; i < 50; i++) cout << \" \" << (best.sel[i] + 1);\n    cout << \"\\n\";\n\n    vector<Point> path;\n    path.reserve(102);\n    path.push_back(OFFICE);\n    for (int i = 0; i < 100; i++) path.push_back(nodePoint(pickPt, delPt, best.seq[i]));\n    path.push_back(OFFICE);\n\n    vector<Point> comp;\n    comp.reserve(path.size());\n    for (auto &p : path) {\n        if (comp.empty() || comp.back().x != p.x || comp.back().y != p.y) comp.push_back(p);\n    }\n\n    cout << (int)comp.size();\n    for (auto &p : comp) cout << \" \" << p.x << \" \" << p.y;\n    cout << \"\\n\";\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <atcoder/all>\n\nusing namespace std;\nusing atcoder::dsu;\n\n// ---------- HLD for max on path (edge values stored on child node positions) ----------\nstruct HLD {\n    int n;\n    vector<vector<pair<int,int>>> g; // to, edgeIndexInMSTAdj(not needed) ; we'll store edge id separately elsewhere\n    vector<int> parent, depth, heavy, head, pos, sz;\n    vector<int> parEdgeD; // d of edge to parent (root=0)\n    vector<int> parEdgeIdx; // original input index of edge to parent (root=-1)\n    int cur;\n\n    HLD(int n=0): n(n) {}\n\n    void build_from_tree(const vector<vector<tuple<int,int,int>>>& tree, int root=0) {\n        // tree[v]: (to, d, inputEdgeIndex)\n        n = (int)tree.size();\n        g.assign(n, {});\n        // We'll keep full info in temporary adjacency\n        // We'll do DFS with that adjacency; no need to fill g.\n        parent.assign(n, -1);\n        depth.assign(n, 0);\n        heavy.assign(n, -1);\n        head.assign(n, 0);\n        pos.assign(n, 0);\n        sz.assign(n, 0);\n        parEdgeD.assign(n, 0);\n        parEdgeIdx.assign(n, -1);\n\n        // Rooting DFS to set parent/depth/parEdge*\n        vector<int> st = {root};\n        parent[root] = -1;\n        depth[root] = 0;\n        vector<int> order;\n        order.reserve(n);\n        while(!st.empty()){\n            int v = st.back(); st.pop_back();\n            order.push_back(v);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                parent[to] = v;\n                depth[to] = depth[v] + 1;\n                parEdgeD[to] = d;\n                parEdgeIdx[to] = idx;\n                st.push_back(to);\n            }\n        }\n        // compute sizes and heavy in reverse order\n        for (int i = (int)order.size()-1; i>=0; --i) {\n            int v = order[i];\n            sz[v] = 1;\n            int bestSize = 0;\n            int bestChild = -1;\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                sz[v] += sz[to];\n                if (sz[to] > bestSize) {\n                    bestSize = sz[to];\n                    bestChild = to;\n                }\n            }\n            heavy[v] = bestChild;\n        }\n\n        // decompose\n        cur = 0;\n        function<void(int,int)> decomp = [&](int v, int h) {\n            head[v] = h;\n            pos[v] = cur++;\n            if (heavy[v] != -1) decomp(heavy[v], h);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v] || to == heavy[v]) continue;\n                decomp(to, to);\n            }\n        };\n        decomp(root, root);\n    }\n\n    template<class Seg>\n    int query_max(int a, int b, Seg &seg) const {\n        int res = 0;\n        int u=a, v=b;\n        while (head[u] != head[v]) {\n            if (depth[head[u]] < depth[head[v]]) swap(u, v);\n            // include head[u] position (its edge to parent is part of path except when head is root; root has 0)\n            res = max(res, seg.prod(pos[head[u]], pos[u] + 1));\n            u = parent[head[u]];\n        }\n        if (depth[u] > depth[v]) swap(u, v);\n        // u is LCA; exclude pos[u] (edge to parent of LCA not on path)\n        res = max(res, seg.prod(pos[u] + 1, pos[v] + 1));\n        return res;\n    }\n};\n\n// segtree for max<int>\nint op_max(int a, int b){ return max(a,b); }\nint e_max(){ return 0; }\n\n// ---------- main ----------\nstatic inline int rounded_dist(int x1,int y1,int x2,int y2){\n    long long dx = x1 - x2;\n    long long dy = y1 - y2;\n    double dist = std::sqrt((double)dx*dx + (double)dy*dy);\n    return (int)llround(dist);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 400;\n    const int M = 1995;\n\n    vector<int> x(N), y(N);\n    for(int i=0;i<N;i++){\n        if(!(cin >> x[i] >> y[i])) return 0;\n    }\n    vector<int> U(M), V(M);\n    for(int i=0;i<M;i++){\n        cin >> U[i] >> V[i];\n    }\n\n    vector<int> D(M);\n    for(int i=0;i<M;i++){\n        D[i] = rounded_dist(x[U[i]], y[U[i]], x[V[i]], y[V[i]]);\n        if (D[i] < 0) D[i] = 0;\n    }\n\n    // Build MST on given edges using weight D[i] (guidance only)\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        if (D[a] != D[b]) return D[a] < D[b];\n        if (U[a] != U[b]) return U[a] < U[b];\n        if (V[a] != V[b]) return V[a] < V[b];\n        return a < b;\n    });\n\n    dsu dsu_mst(N);\n    vector<char> inMST(M, false);\n    vector<vector<tuple<int,int,int>>> tree(N); // to, d, inputIndex\n    int picked = 0;\n    for(int idx: ord){\n        if (picked == N-1) break;\n        int u=U[idx], v=V[idx];\n        if(dsu_mst.same(u,v)) continue;\n        dsu_mst.merge(u,v);\n        inMST[idx]=true;\n        picked++;\n        tree[u].push_back({v, D[idx], idx});\n        tree[v].push_back({u, D[idx], idx});\n    }\n    // (Graph guaranteed connected, so picked==N-1)\n\n    // Build HLD + segtree on this MST\n    HLD hld;\n    hld.build_from_tree(tree, 0);\n\n    // map input edge index -> child node in rooted MST (for updates)\n    vector<int> idxToChild(M, -1);\n    for(int v=1; v<N; v++){\n        int idx = hld.parEdgeIdx[v];\n        if(idx >= 0) idxToChild[idx] = v;\n    }\n\n    vector<int> init(N, 0);\n    for(int v=1; v<N; v++){\n        init[hld.pos[v]] = hld.parEdgeD[v]; // edge value on child position\n    }\n    atcoder::segtree<int, op_max, e_max> seg(init);\n\n    // Adopted forest DSU\n    dsu dsu_acc(N);\n    vector<pair<int,int>> adopted;\n    adopted.reserve(N-1);\n    int comps = N;\n\n    auto can_reject = [&](int i)->bool{\n        dsu tmp(N);\n        for(auto &e: adopted) tmp.merge(e.first, e.second);\n        for(int j=i+1;j<M;j++){\n            tmp.merge(U[j], V[j]);\n        }\n        return tmp.size(0) == N;\n    };\n\n    for(int i=0;i<M;i++){\n        int l;\n        if(!(cin >> l)) break;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        if (comps == 1) {\n            ans = 0;\n        } else if (dsu_acc.same(u,v)) {\n            ans = 0; // never take cycle edges\n        } else {\n            bool okReject = can_reject(i);\n            bool take = false;\n\n            if (!okReject) {\n                take = true; // forced (bridge in remaining available graph)\n            } else {\n                // dynamic thresholds (mildly relaxed near the end / when urgent)\n                double t = (M <= 1) ? 1.0 : (double)i / (double)(M-1);\n                double remain = max(1, (M-1-i));\n                double need = comps - 1;\n                double urg = need / remain;           // ~0..>1 (cap below)\n                double mult = 1.0 + 0.8 * min(1.0, urg);\n\n                auto cap3 = [&](double r){ return min(3.0, r); };\n                int cheapR = (int)llround(cap3((1.35 + 0.35*t) * mult) * 1000.0);  // vs D[i]\n                int replR  = (int)llround(cap3((1.75 + 0.35*t) * mult) * 1000.0);  // vs md\n                int treeR  = (int)llround(cap3((2.10 + 0.30*t) * mult) * 1000.0);  // MST edges slightly looser\n\n                long long L = l;\n                long long di = D[i];\n\n                // If it's an MST edge and not too bad, often keep it.\n                if (inMST[i] && L*1000LL <= di * (long long)treeR) take = true;\n\n                // Very cheap by its own distance\n                if (!take && L*1000LL <= di * (long long)cheapR) take = true;\n\n                // Competitive compared to remaining MST bottleneck on u-v path\n                if (!take) {\n                    int md = hld.query_max(u, v, seg); // max remaining D on MST path\n                    if (md > 0) {\n                        // require di not much larger than md (di <= 1.25*md)\n                        if (di*1000LL <= (long long)md * 1250LL &&\n                            L*1000LL <= (long long)md * (long long)replR) {\n                            take = true;\n                        }\n                    }\n                }\n            }\n\n            if (take) {\n                dsu_acc.merge(u,v);\n                adopted.push_back({u,v});\n                comps--;\n                ans = 1;\n            } else {\n                ans = 0;\n            }\n        }\n\n        cout << ans << \"\\n\";\n        cout.flush();\n\n        // Remove MST edge from \"future MST edges\" structure once its index is processed\n        if (inMST[i]) {\n            int child = idxToChild[i];\n            if (child != -1) seg.set(hld.pos[child], 0);\n        }\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 30, W = 30;\nstatic constexpr int INF = 1e9;\n\nstruct Pet { int x, y, t; };\nstruct Human { int x, y; };\n\nstruct Rect { int x1, x2, y1, y2; }; // inclusive\n\nstatic inline bool inb(int x,int y){ return 1<=x && x<=H && 1<=y && y<=W; }\nstatic inline int manhattan(int ax,int ay,int bx,int by){ return abs(ax-bx)+abs(ay-by); }\n\nstatic const int dx4[4] = {-1,+1,0,0};\nstatic const int dy4[4] = {0,0,-1,+1};\nstatic const char MOVE_CH[4]  = {'U','D','L','R'};\nstatic const char BUILD_CH[4] = {'u','d','l','r'};\n\nstruct DoorInfo {\n    int x=-1,y=-1;\n    int inx=-1, iny=-1; // inside neighbor (must be in rect)\n    long long score=LLONG_MIN;\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N; cin >> N;\n    vector<Pet> pets(N);\n    for(int i=0;i<N;i++) cin >> pets[i].x >> pets[i].y >> pets[i].t;\n\n    int M; cin >> M;\n    vector<Human> humans(M);\n    for(int i=0;i<M;i++) cin >> humans[i].x >> humans[i].y;\n\n    auto inside = [&](const Rect& r, int x, int y)->bool{\n        return r.x1 <= x && x <= r.x2 && r.y1 <= y && y <= r.y2;\n    };\n\n    auto make_rect = [&](int corner, int h, int w)->Rect{\n        Rect r;\n        if(corner==0){ r.x1=1; r.x2=h; r.y1=1; r.y2=w; }                   // TL\n        if(corner==1){ r.x1=1; r.x2=h; r.y1=W-w+1; r.y2=W; }               // TR\n        if(corner==2){ r.x1=H-h+1; r.x2=H; r.y1=1; r.y2=w; }               // BL\n        if(corner==3){ r.x1=H-h+1; r.x2=H; r.y1=W-w+1; r.y2=W; }           // BR\n        return r;\n    };\n\n    auto wall_cells_for = [&](const Rect& r)->vector<pair<int,int>>{\n        vector<pair<int,int>> cells;\n        if(r.x1 > 1){\n            int x = r.x1 - 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.x2 < H){\n            int x = r.x2 + 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.y1 > 1){\n            int y = r.y1 - 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        if(r.y2 < W){\n            int y = r.y2 + 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        return cells;\n    };\n\n    auto count_pets_in_rect = [&](const Rect& r)->int{\n        int cnt=0;\n        for(auto &p: pets) if(inside(r,p.x,p.y)) cnt++;\n        return cnt;\n    };\n\n    auto dist_pet_to_rect = [&](const Rect& r)->int{\n        int best = INF;\n        for(auto &p: pets){\n            int dx = 0;\n            if(p.x < r.x1) dx = r.x1 - p.x;\n            else if(p.x > r.x2) dx = p.x - r.x2;\n            int dy = 0;\n            if(p.y < r.y1) dy = r.y1 - p.y;\n            else if(p.y > r.y2) dy = p.y - r.y2;\n            best = min(best, dx+dy);\n        }\n        return best;\n    };\n\n    auto max_human_dist_to_rect = [&](const Rect& r)->int{\n        int mx=0;\n        for(auto &hu: humans){\n            int dx=0;\n            if(hu.x < r.x1) dx = r.x1 - hu.x;\n            else if(hu.x > r.x2) dx = hu.x - r.x2;\n            int dy=0;\n            if(hu.y < r.y1) dy = r.y1 - hu.y;\n            else if(hu.y > r.y2) dy = hu.y - r.y2;\n            mx = max(mx, dx+dy);\n        }\n        return mx;\n    };\n\n    auto choose_doors = [&](const Rect& r, const vector<pair<int,int>>& wallCells, int K)->vector<DoorInfo>{\n        static bool isWall[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) isWall[x][y]=false;\n        for(auto [x,y]: wallCells) isWall[x][y]=true;\n\n        vector<DoorInfo> cand;\n        cand.reserve((int)wallCells.size());\n        for(auto [wx,wy]: wallCells){\n            int inx=-1, iny=-1;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(inb(nx,ny) && inside(r,nx,ny)){ inx=nx; iny=ny; break; }\n            }\n            if(inx==-1) continue;\n\n            bool okOutside=false;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(inside(r,nx,ny)) continue;\n                if(isWall[nx][ny]) continue;\n                okOutside=true;\n            }\n            if(!okOutside) continue;\n\n            int minPetDist = 1000;\n            for(auto &p: pets) minPetDist = min(minPetDist, manhattan(wx,wy,p.x,p.y));\n\n            long long sumHumanDist = 0;\n            for(auto &h: humans) sumHumanDist += manhattan(h.x,h.y, inx,iny);\n\n            // Slightly prefer doors not on outer border\n            int borderPenalty = (wx==1 || wx==H || wy==1 || wy==W) ? 50 : 0;\n\n            DoorInfo di;\n            di.x=wx; di.y=wy; di.inx=inx; di.iny=iny;\n            di.score = 250LL*minPetDist - 1LL*sumHumanDist - borderPenalty;\n            cand.push_back(di);\n        }\n        sort(cand.begin(), cand.end(), [&](const DoorInfo& a, const DoorInfo& b){\n            return a.score > b.score;\n        });\n\n        vector<DoorInfo> res;\n        for(auto &d: cand){\n            bool far=true;\n            for(auto &e: res){\n                if(manhattan(d.x,d.y,e.x,e.y) < 5){ far=false; break; }\n            }\n            if(!far) continue;\n            res.push_back(d);\n            if((int)res.size()>=K) break;\n        }\n        // if couldn't pick far enough, just take top\n        for(auto &d: cand){\n            if((int)res.size()>=K) break;\n            bool used=false;\n            for(auto &e: res) if(e.x==d.x && e.y==d.y) used=true;\n            if(!used) res.push_back(d);\n        }\n        return res;\n    };\n\n    // Select rectangle (more conservative: smaller, faster to build)\n    Rect bestRect{1,5,1,5};\n    vector<DoorInfo> bestDoors;\n    double bestEval = -1e100;\n\n    for(int corner=0; corner<4; corner++){\n        for(int h=5; h<=15; h++){\n            for(int w=5; w<=15; w++){\n                Rect r = make_rect(corner,h,w);\n                int area = (r.x2-r.x1+1)*(r.y2-r.y1+1);\n\n                int petsIn = count_pets_in_rect(r);\n                int minPetToRect = dist_pet_to_rect(r);\n                int maxHumanDist = max_human_dist_to_rect(r);\n\n                auto wallCells = wall_cells_for(r);\n                int wallLen = (int)wallCells.size();\n\n                // doors: 2 for longer fences, else 1\n                int K = (wallLen >= 24 ? 2 : 1);\n                auto doors = choose_doors(r, wallCells, K);\n                if((int)doors.size() < K) continue;\n\n                // must avoid initial human/pet on wall cells (too troublesome early)\n                bool bad=false;\n                for(auto [x,y]: wallCells){\n                    for(auto &p: pets) if(p.x==x && p.y==y){ bad=true; break; }\n                    if(bad) break;\n                    for(auto &hu: humans) if(hu.x==x && hu.y==y){ bad=true; break; }\n                    if(bad) break;\n                }\n                if(bad) continue;\n\n                // Heuristic evaluation (robustness-oriented)\n                double val = (double)area / 900.0;\n\n                // heavily penalize having pets initially inside\n                if(petsIn==0) val *= 1.0;\n                else val *= pow(0.5, 3.0*petsIn);\n\n                // prefer far from pets and not too far for humans\n                val *= (1.0 + 0.06 * minPetToRect);\n                val *= exp(-0.05 * maxHumanDist);\n\n                // penalize longer fences to avoid slow builds\n                val *= exp(-0.08 * wallLen);\n\n                // discourage choosing rectangles too close to pets\n                if(minPetToRect <= 1) val *= 0.2;\n\n                if(val > bestEval){\n                    bestEval = val;\n                    bestRect = r;\n                    bestDoors = doors;\n                }\n            }\n        }\n    }\n\n    Rect rect = bestRect;\n    auto wallCells = wall_cells_for(rect);\n\n    // State of blocked cells\n    static bool blocked[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) blocked[x][y]=false;\n\n    // Target wall cells to block (excluding doors)\n    static bool targetWall[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) targetWall[x][y]=false;\n    for(auto [x,y]: wallCells) targetWall[x][y]=true;\n\n    // Exclude door cells from targetWall\n    for(auto &d: bestDoors){\n        if(d.x!=-1) targetWall[d.x][d.y]=false;\n    }\n\n    vector<bool> doorClosed(bestDoors.size(), false);\n\n    // Gather point: inside, near the best door's inside neighbor, pushed deeper if possible.\n    pair<int,int> gatherPoint;\n    {\n        DoorInfo d0 = bestDoors[0];\n        int gx = d0.inx, gy = d0.iny;\n        int vx = d0.inx - d0.x;\n        int vy = d0.iny - d0.y;\n        int gx2 = gx + vx, gy2 = gy + vy;\n        if(inb(gx2,gy2) && inside(rect,gx2,gy2)){ gx=gx2; gy=gy2; }\n        gatherPoint = {gx,gy};\n    }\n\n    auto compute_occupancy = [&](vector<vector<bool>>& petAt, vector<vector<bool>>& humanAt){\n        petAt.assign(H+1, vector<bool>(W+1,false));\n        humanAt.assign(H+1, vector<bool>(W+1,false));\n        for(auto &p: pets) petAt[p.x][p.y]=true;\n        for(auto &h: humans) humanAt[h.x][h.y]=true;\n    };\n\n    auto canBuild = [&](int tx,int ty,\n                        const vector<vector<bool>>& petAt,\n                        const vector<vector<bool>>& humanAt)->bool{\n        if(!inb(tx,ty)) return false;\n        if(petAt[tx][ty] || humanAt[tx][ty]) return false;\n        for(int d=0; d<4; d++){\n            int nx=tx+dx4[d], ny=ty+dy4[d];\n            if(inb(nx,ny) && petAt[nx][ny]) return false;\n        }\n        return true;\n    };\n\n    auto bfs_dist = [&](vector<vector<int>>& dist,\n                        const vector<pair<int,int>>& sources,\n                        function<bool(int,int)> passable){\n        dist.assign(H+1, vector<int>(W+1, INF));\n        deque<pair<int,int>> q;\n        for(auto [sx,sy]: sources){\n            if(!inb(sx,sy)) continue;\n            if(!passable(sx,sy)) continue;\n            dist[sx][sy]=0;\n            q.push_back({sx,sy});\n        }\n        while(!q.empty()){\n            auto [x,y]=q.front(); q.pop_front();\n            int nd = dist[x][y]+1;\n            for(int d=0; d<4; d++){\n                int nx=x+dx4[d], ny=y+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(!passable(nx,ny)) continue;\n                if(dist[nx][ny] > nd){\n                    dist[nx][ny]=nd;\n                    q.push_back({nx,ny});\n                }\n            }\n        }\n    };\n\n    auto step_by_dist = [&](int x,int y, const vector<vector<int>>& dist,\n                            function<bool(int,int)> passable,\n                            function<int(int,int)> tiePenalty)->char{\n        int cur = dist[x][y];\n        int bestDir=-1;\n        int bestD=cur;\n        int bestPen=INF;\n        for(int d=0; d<4; d++){\n            int nx=x+dx4[d], ny=y+dy4[d];\n            if(!inb(nx,ny)) continue;\n            if(!passable(nx,ny)) continue;\n            if(dist[nx][ny] < bestD){\n                bestD = dist[nx][ny];\n                bestPen = tiePenalty(nx,ny);\n                bestDir = d;\n            }else if(dist[nx][ny] == bestD && bestDir!=-1){\n                int pen = tiePenalty(nx,ny);\n                if(pen < bestPen){\n                    bestPen = pen;\n                    bestDir = d;\n                }\n            }\n        }\n        if(bestDir==-1 || bestD>=cur) return '.';\n        return MOVE_CH[bestDir];\n    };\n\n    for(int turn=0; turn<300; turn++){\n        vector<vector<bool>> petAt, humanAt;\n        compute_occupancy(petAt, humanAt);\n\n        auto insideNow = [&](int x,int y){ return inside(rect,x,y); };\n\n        int remWalls=0;\n        for(auto [x,y]: wallCells){\n            if(targetWall[x][y] && !blocked[x][y]) remWalls++;\n        }\n\n        int remDoors=0;\n        for(int i=0;i<(int)bestDoors.size();i++){\n            if(!doorClosed[i] && !blocked[bestDoors[i].x][bestDoors[i].y]) remDoors++;\n        }\n\n        bool allInside = true;\n        for(auto &h: humans){\n            if(!insideNow(h.x,h.y)){ allInside=false; break; }\n        }\n\n        // Passability for movement: just avoid already blocked\n        auto passAll = [&](int x,int y)->bool{\n            return inb(x,y) && !blocked[x][y];\n        };\n        auto passInside = [&](int x,int y)->bool{\n            return inb(x,y) && insideNow(x,y) && !blocked[x][y];\n        };\n\n        // Build goals: inside cells adjacent to remaining target walls\n        vector<pair<int,int>> buildGoals;\n        if(remWalls>0){\n            static bool mark[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark[x][y]=false;\n            for(auto [wx,wy]: wallCells){\n                if(!(targetWall[wx][wy] && !blocked[wx][wy])) continue;\n                for(int d=0; d<4; d++){\n                    int nx=wx+dx4[d], ny=wy+dy4[d];\n                    if(inb(nx,ny) && insideNow(nx,ny) && !blocked[nx][ny]){\n                        if(!mark[nx][ny]){\n                            mark[nx][ny]=true;\n                            buildGoals.push_back({nx,ny});\n                        }\n                    }\n                }\n            }\n        }\n\n        vector<vector<int>> distGather, distBuild, distClose;\n        bfs_dist(distGather, {gatherPoint}, passAll);\n\n        if(!buildGoals.empty()) bfs_dist(distBuild, buildGoals, passInside);\n        else distBuild.assign(H+1, vector<int>(W+1, INF));\n\n        // Door inside-neighbor cells for closing phase\n        vector<pair<int,int>> closeGoals;\n        if(remWalls==0 && remDoors>0 && allInside){\n            static bool mark2[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark2[x][y]=false;\n            for(int i=0;i<(int)bestDoors.size();i++){\n                if(doorClosed[i]) continue;\n                auto &d = bestDoors[i];\n                if(blocked[d.x][d.y]) { doorClosed[i]=true; continue; }\n                if(inb(d.inx,d.iny) && insideNow(d.inx,d.iny) && !blocked[d.inx][d.iny]){\n                    if(!mark2[d.inx][d.iny]){\n                        mark2[d.inx][d.iny]=true;\n                        closeGoals.push_back({d.inx,d.iny});\n                    }\n                }\n            }\n        }\n        if(!closeGoals.empty()) bfs_dist(distClose, closeGoals, passInside);\n        else distClose.assign(H+1, vector<int>(W+1, INF));\n\n        vector<char> act(M,'.');\n\n        // 1) Try to close doors (if fence walls are done and all humans inside)\n        if(remWalls==0 && allInside){\n            // attempt close multiple doors per turn\n            for(int di=0; di<(int)bestDoors.size(); di++){\n                if(doorClosed[di]) continue;\n                auto &d = bestDoors[di];\n                if(blocked[d.x][d.y]) { doorClosed[di]=true; continue; }\n                if(!canBuild(d.x,d.y,petAt,humanAt)) continue;\n\n                // find an unassigned human adjacent to door\n                for(int i=0;i<M;i++){\n                    if(act[i] != '.') continue;\n                    int hx=humans[i].x, hy=humans[i].y;\n                    if(manhattan(hx,hy,d.x,d.y)!=1) continue;\n                    for(int dir=0; dir<4; dir++){\n                        if(hx+dx4[dir]==d.x && hy+dy4[dir]==d.y){\n                            act[i]=BUILD_CH[dir];\n                            break;\n                        }\n                    }\n                    if(act[i] != '.'){\n                        // mark to close in local sim later\n                        break;\n                    }\n                }\n            }\n        }\n\n        // 2) Build any adjacent remaining target wall cell (any human, inside or outside)\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n            for(int dir=0; dir<4; dir++){\n                int tx=hx+dx4[dir], ty=hy+dy4[dir];\n                if(!inb(tx,ty)) continue;\n                if(targetWall[tx][ty] && !blocked[tx][ty]){\n                    if(canBuild(tx,ty,petAt,humanAt)){\n                        act[i]=BUILD_CH[dir];\n                        break;\n                    }\n                }\n            }\n        }\n\n        // 3) Move\n        auto tiePenaltyAll = [&](int x,int y)->int{\n            // discourage stopping on target wall cells that will be built (to reduce blocking builds)\n            if(targetWall[x][y] && !blocked[x][y]) return 10;\n            return 0;\n        };\n        auto tiePenaltyInside = [&](int x,int y)->int{\n            return 0;\n        };\n\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            if(!insideNow(hx,hy)){\n                if(distGather[hx][hy] >= INF){\n                    act[i]='.';\n                }else{\n                    act[i] = step_by_dist(hx,hy,distGather,passAll,tiePenaltyAll);\n                }\n            }else{\n                if(remWalls>0 && distBuild[hx][hy] < INF){\n                    act[i] = step_by_dist(hx,hy,distBuild,passInside,tiePenaltyInside);\n                }else if(remWalls==0 && remDoors>0 && allInside && distClose[hx][hy] < INF){\n                    act[i] = step_by_dist(hx,hy,distClose,passInside,tiePenaltyInside);\n                }else{\n                    act[i]='.';\n                }\n            }\n        }\n\n        string out;\n        out.reserve(M);\n        for(int i=0;i<M;i++) out.push_back(act[i]);\n        cout << out << \"\\n\" << flush;\n\n        // ---- Local simulation update (humans + blocks) ----\n        static bool willBeBlocked[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) willBeBlocked[x][y]=false;\n\n        // Apply builds (successful)\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='u') dir=0;\n            if(c=='d') dir=1;\n            if(c=='l') dir=2;\n            if(c=='r') dir=3;\n            if(dir==-1) continue;\n            int tx=humans[i].x+dx4[dir], ty=humans[i].y+dy4[dir];\n            if(inb(tx,ty) && canBuild(tx,ty,petAt,humanAt)){\n                willBeBlocked[tx][ty]=true;\n            }\n        }\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n            if(willBeBlocked[x][y]) blocked[x][y]=true;\n        }\n\n        // Apply moves\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='U') dir=0;\n            if(c=='D') dir=1;\n            if(c=='L') dir=2;\n            if(c=='R') dir=3;\n            if(dir==-1) continue;\n            int nx=humans[i].x+dx4[dir], ny=humans[i].y+dy4[dir];\n            if(inb(nx,ny) && !blocked[nx][ny] && !willBeBlocked[nx][ny]){\n                humans[i].x=nx; humans[i].y=ny;\n            }\n        }\n\n        // Update doorClosed flags if doors got blocked this turn\n        for(int i=0;i<(int)bestDoors.size();i++){\n            if(doorClosed[i]) continue;\n            auto &d=bestDoors[i];\n            if(blocked[d.x][d.y]) doorClosed[i]=true;\n        }\n\n        // ---- Read pet moves and update pets ----\n        for(int i=0;i<N;i++){\n            string s; cin >> s;\n            if(s==\".\") continue;\n            for(char c: s){\n                int dir=-1;\n                if(c=='U') dir=0;\n                if(c=='D') dir=1;\n                if(c=='L') dir=2;\n                if(c=='R') dir=3;\n                if(dir==-1) continue;\n                int nx=pets[i].x+dx4[dir], ny=pets[i].y+dy4[dir];\n                if(inb(nx,ny) && !blocked[nx][ny]){\n                    pets[i].x=nx; pets[i].y=ny;\n                }\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int V = N * N;\nstatic constexpr int INF = 1e9;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() : st(chrono::high_resolution_clock::now()) {}\n    double elapsed() const {\n        auto ed = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(ed - st).count();\n    }\n};\n\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3; // 'R'\n}\nstatic inline char dirCh(int d) {\n    static const char dc[4] = {'U','D','L','R'};\n    return dc[d];\n}\nstatic inline char oppDir(char c){\n    if(c=='U') return 'D';\n    if(c=='D') return 'U';\n    if(c=='L') return 'R';\n    return 'L';\n}\n\nstruct Evaluator {\n    int s, t;\n    float p, q;\n    const int (*nxt)[4];\n    array<float, V> dist{}, ndist{};\n\n    Evaluator(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p((float)p_), q((float)(1.0 - p_)), nxt(nxt_) {}\n\n    double eval(const string &seq) {\n        dist.fill(0.0f);\n        ndist.fill(0.0f);\n        dist[s] = 1.0f;\n        double E = 0.0;\n        const int L = (int)seq.size();\n        for (int step = 0; step < L; step++) {\n            ndist.fill(0.0f);\n            const int d = dirId(seq[step]);\n            double hit = 0.0;\n\n            for (int pos = 0; pos < V; pos++) {\n                float pr = dist[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    ndist[pos] += pr;\n                } else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    ndist[pos] += st;\n                    if (np == t) hit += (double)mv;\n                    else ndist[np] += mv;\n                }\n            }\n            dist = ndist;\n            E += hit * (401.0 - (step + 1));\n        }\n        return E;\n    }\n};\n\nstruct Meta {\n    int parent;\n    char mv;\n};\n\nstruct Cand {\n    int meta;\n    double exp;      // accumulated expected score so far\n    double key;      // beam sort key\n    float rem;       // remaining probability mass not yet reached\n    float avgd;      // avg dist-to-target under remaining mass (for sorting diversity)\n    array<float, V> prob;\n};\n\nstatic string reconstruct(const vector<Meta>& meta, int node) {\n    string s;\n    while (node != 0) {\n        s.push_back(meta[node].mv);\n        node = meta[node].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nstatic string shortest_path_tiled_200(int s, int t, const int nxt[V][4]) {\n    vector<int> prev(V, -1);\n    vector<char> prevC(V, '?');\n    deque<int> dq;\n    dq.push_back(s);\n    prev[s] = s;\n\n    while (!dq.empty()) {\n        int x = dq.front(); dq.pop_front();\n        if (x == t) break;\n        for (int d = 0; d < 4; d++) {\n            int y = nxt[x][d];\n            if (y == x) continue;\n            if (prev[y] != -1) continue;\n            prev[y] = x;\n            prevC[y] = dirCh(d);\n            dq.push_back(y);\n        }\n    }\n    // reconstruct\n    string path;\n    if (prev[t] == -1) {\n        // should not happen (reachable guaranteed). fallback: arbitrary.\n        path = \"D\";\n    } else {\n        int cur = t;\n        while (cur != s) {\n            path.push_back(prevC[cur]);\n            cur = prev[cur];\n        }\n        reverse(path.begin(), path.end());\n    }\n    if (path.empty()) path = \"D\";\n\n    string out;\n    out.reserve(200);\n    while ((int)out.size() < 200) out += path;\n    out.resize(200);\n    return out;\n}\n\nstatic string beam_search_200(\n    int s, int t, double p,\n    const int nxt[V][4],\n    const vector<int>& distToT,\n    Timer &timer,\n    double timeLimitSec\n) {\n    const double q = 1.0 - p;\n    int W = (p >= 0.35 ? 900 : 750); // slightly wider than before\n\n    // Keep some candidates by different criteria to avoid brittle pruning\n    int keepKey = (int)(W * 0.55);\n    int keepExp = (int)(W * 0.25);\n    int keepRem = W - keepKey - keepExp;\n\n    vector<Meta> meta;\n    meta.reserve(300000);\n    meta.push_back({-1, '?'});\n\n    vector<Cand> cur;\n    cur.reserve(W);\n\n    Cand root;\n    root.meta = 0;\n    root.exp = 0.0;\n    root.key = 0.0;\n    root.rem = 1.0f;\n    root.avgd = (float)distToT[s];\n    root.prob.fill(0.0f);\n    root.prob[s] = 1.0f;\n    if (s == t) {\n        root.prob[s] = 0.0f;\n        root.rem = 0.0f;\n        root.avgd = 0.0f;\n    }\n    cur.push_back(root);\n\n    for (int depth = 0; depth < 200; depth++) {\n        if (timer.elapsed() > timeLimitSec) break;\n\n        vector<Cand> all;\n        all.reserve(cur.size() * 4);\n\n        for (const auto &c : cur) {\n            if (c.rem < 1e-12f) continue;\n\n            for (int d = 0; d < 4; d++) {\n                Cand ch;\n                ch.prob.fill(0.0f);\n                double hit = 0.0;\n\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = c.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    int np = nxt[pos][d];\n                    if (np == pos) {\n                        ch.prob[pos] += prf;\n                    } else {\n                        double pr = (double)prf;\n                        double mv = pr * q;\n                        double st = pr * p;\n                        if (np == t) hit += mv;\n                        else ch.prob[np] += (float)mv;\n                        ch.prob[pos] += (float)st;\n                    }\n                }\n\n                int turn = depth + 1;\n                ch.exp = c.exp + hit * (401.0 - turn);\n\n                double rem = 0.0, sumd = 0.0;\n                int mind = INF;\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = ch.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    rem += prf;\n                    int dtt = distToT[pos];\n                    sumd += (double)prf * dtt;\n                    mind = min(mind, dtt);\n                }\n                ch.rem = (float)rem;\n                ch.avgd = (rem > 1e-12 ? (float)(sumd / rem) : 0.0f);\n\n                // Heuristic key: current exp + remaining mass * (optimistic future reward estimate)\n                double key = ch.exp;\n                int remainingSteps = 200 - turn;\n                if (rem > 1e-12 && mind <= remainingSteps) {\n                    double avgd = sumd / max(rem, 1e-12);\n                    // forgetting makes effective progress slower ~1/q\n                    double estTime = (double)turn + avgd / max(1e-6, q);\n                    estTime = min(estTime, 200.0);\n                    double estAdd = rem * max(0.0, 401.0 - estTime);\n                    // also slightly reward having already reached some probability mass\n                    double reached = 1.0 - rem;\n                    key = ch.exp + 0.85 * estAdd + 8.0 * reached;\n                }\n                ch.key = key;\n\n                meta.push_back({c.meta, dirCh(d)});\n                ch.meta = (int)meta.size() - 1;\n\n                all.push_back(std::move(ch));\n            }\n        }\n\n        if (all.empty()) break;\n\n        int M = (int)all.size();\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        vector<char> chosen(M, 0);\n        vector<int> picked;\n        picked.reserve(min(W, M));\n\n        auto pickTop = [&](int need, auto cmp) {\n            if (need <= 0) return;\n            vector<int> id = idx;\n            need = min(need, (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(), cmp);\n            id.resize(need);\n            sort(id.begin(), id.end(), cmp);\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) {\n                    chosen[i] = 1;\n                    picked.push_back(i);\n                }\n            }\n        };\n\n        // By key\n        pickTop(keepKey, [&](int a, int b){ return all[a].key > all[b].key; });\n        // By exp (exact so far)\n        pickTop(keepExp, [&](int a, int b){ return all[a].exp > all[b].exp; });\n        // By remaining mass (smaller rem is better => already reached more)\n        pickTop(keepRem, [&](int a, int b){ return all[a].rem < all[b].rem; });\n\n        // If still not enough (due to duplicates), fill by key\n        if ((int)picked.size() < min(W, M)) {\n            vector<int> id = idx;\n            int need = min(W - (int)picked.size(), (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(),\n                        [&](int a, int b){ return all[a].key > all[b].key; });\n            id.resize(need);\n            sort(id.begin(), id.end(), [&](int a, int b){ return all[a].key > all[b].key; });\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) {\n                    chosen[i] = 1;\n                    picked.push_back(i);\n                }\n            }\n        }\n\n        vector<Cand> nb;\n        nb.reserve(picked.size());\n        for (int i : picked) nb.push_back(std::move(all[i]));\n        cur.swap(nb);\n    }\n\n    // Choose best by exp among current beam\n    int bestMeta = cur[0].meta;\n    double bestExp = cur[0].exp;\n    for (auto &c : cur) {\n        if (c.exp > bestExp) {\n            bestExp = c.exp;\n            bestMeta = c.meta;\n        }\n    }\n\n    string ans = reconstruct(meta, bestMeta);\n    if ((int)ans.size() < 200) ans.append(200 - ans.size(), 'U');\n    if ((int)ans.size() > 200) ans.resize(200);\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TL = 1.97;         // total internal budget\n    const double BEAM_TL = 0.85;    // budget for beam (leave room for SA)\n\n    int si, sj, ti, tj;\n    double p;\n    cin >> si >> sj >> ti >> tj >> p;\n\n    vector<string> h(N);\n    for (int i = 0; i < N; i++) cin >> h[i];\n    vector<string> v(N - 1);\n    for (int i = 0; i < N - 1; i++) cin >> v[i];\n\n    auto id = [&](int r, int c){ return r * N + c; };\n    int s = id(si, sj);\n    int t = id(ti, tj);\n\n    // Precompute transitions with walls.\n    static int nxt[V][4];\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int cur = id(r, c);\n        // U\n        if (r == 0) nxt[cur][0] = cur;\n        else nxt[cur][0] = (v[r-1][c] == '0') ? id(r-1, c) : cur;\n        // D\n        if (r == N-1) nxt[cur][1] = cur;\n        else nxt[cur][1] = (v[r][c] == '0') ? id(r+1, c) : cur;\n        // L\n        if (c == 0) nxt[cur][2] = cur;\n        else nxt[cur][2] = (h[r][c-1] == '0') ? id(r, c-1) : cur;\n        // R\n        if (c == N-1) nxt[cur][3] = cur;\n        else nxt[cur][3] = (h[r][c] == '0') ? id(r, c+1) : cur;\n    }\n\n    // Distances to target (BFS on undirected grid-with-walls graph).\n    vector<int> distToT(V, INF);\n    {\n        deque<int> dq;\n        distToT[t] = 0;\n        dq.push_back(t);\n        while (!dq.empty()) {\n            int x = dq.front(); dq.pop_front();\n            int dx = distToT[x] + 1;\n            for (int d = 0; d < 4; d++) {\n                int y = nxt[x][d];\n                if (y == x) continue;\n                if (distToT[y] > dx) {\n                    distToT[y] = dx;\n                    dq.push_back(y);\n                }\n            }\n        }\n    }\n\n    Evaluator evaluator(s, t, p, nxt);\n\n    // Candidate 1: beam search\n    string ans1 = beam_search_200(s, t, p, nxt, distToT, timer, BEAM_TL);\n    double sc1 = evaluator.eval(ans1);\n\n    // Candidate 2: shortest path repeated to length 200 (diversification)\n    string ans2 = shortest_path_tiled_200(s, t, nxt);\n    double sc2 = evaluator.eval(ans2);\n\n    string best = (sc2 > sc1 ? ans2 : ans1);\n    double bestScore = max(sc1, sc2);\n\n    // Quick greedy single-position improvement (one pass, randomized order)\n    {\n        if (timer.elapsed() < TL * 0.55) {\n            string cur = best;\n            double curScore = bestScore;\n\n            vector<int> order(200);\n            iota(order.begin(), order.end(), 0);\n            std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int idx : order) {\n                if (timer.elapsed() > TL * 0.70) break;\n                char orig = cur[idx];\n                double localBestScore = curScore;\n                char localBestChar = orig;\n                for (int d = 0; d < 4; d++) {\n                    char c = dirCh(d);\n                    if (c == orig) continue;\n                    cur[idx] = c;\n                    double scc = evaluator.eval(cur);\n                    if (scc > localBestScore) {\n                        localBestScore = scc;\n                        localBestChar = c;\n                    }\n                }\n                cur[idx] = localBestChar;\n                curScore = localBestScore;\n            }\n\n            if (curScore > bestScore) {\n                bestScore = curScore;\n                best = cur;\n            }\n        }\n    }\n\n    // Simulated annealing until time limit\n    {\n        std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n        auto rnd01 = [&]() -> double {\n            return (double)rng() / (double)rng.max();\n        };\n        auto rndi = [&](int lo, int hi) -> int { // inclusive\n            std::uniform_int_distribution<int> dist(lo, hi);\n            return dist(rng);\n        };\n\n        string cur = best;\n        double curScore = bestScore;\n\n        const double T0 = 2.0;   // on E[S] scale (~0..400)\n        const double T1 = 0.05;\n\n        while (timer.elapsed() < TL) {\n            double tsec = timer.elapsed();\n            double frac = min(1.0, max(0.0, (tsec - 0.70) / max(1e-9, (TL - 0.70))));\n            double temp = T0 * pow(T1 / T0, frac);\n\n            int type = rndi(0, 99);\n            if (type < 60) {\n                // single change\n                int i = rndi(0, 199);\n                char old = cur[i];\n                char nc = dirCh(rndi(0, 3));\n                if (nc == old) continue;\n                cur[i] = nc;\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    cur[i] = old;\n                }\n            } else if (type < 85) {\n                // swap\n                int i = rndi(0, 199), j = rndi(0, 199);\n                if (i == j) continue;\n                swap(cur[i], cur[j]);\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    swap(cur[i], cur[j]);\n                }\n            } else {\n                // randomize short segment\n                int l = rndi(0, 199);\n                int len = rndi(2, 8);\n                int r = min(200, l + len);\n                string old = cur.substr(l, r - l);\n                for (int i = l; i < r; i++) cur[i] = dirCh(rndi(0, 3));\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    for (int i = l; i < r; i++) cur[i] = old[i - l];\n                }\n            }\n        }\n    }\n\n    cout << best << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TILES = N * N;\nstatic constexpr int PORTS = TILES * 4;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU64() % (uint64_t)(hi - lo + 1));\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct EvalResult {\n    long long baseScore;     // L1*L2 (true score if >=2 loops else 0)\n    int L1, L2;\n    int loopCount;\n    int compCount;\n    int matchedEdges;        // active-active borders\n    int openEnds;            // endpoints with deg==1\n    int largestCompLen;      // max(compSize/2) over all components (loops or paths)\n    long long sumCompLenSq;  // sum (compLen^2) over all components\n    double energy;           // SA energy\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Input\n    vector<uint8_t> initState(TILES);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) initState[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    // Rotation map (90deg CCW)\n    // 0->1->2->3->0, 4<->5, 6<->7\n    array<uint8_t, 8> rot1 = {1,2,3,0,5,4,7,6};\n    uint8_t rotStep[8][4];\n    for (int t = 0; t < 8; t++) {\n        rotStep[t][0] = (uint8_t)t;\n        rotStep[t][1] = rot1[t];\n        rotStep[t][2] = rot1[rotStep[t][1]];\n        rotStep[t][3] = rot1[rotStep[t][2]];\n    }\n\n    // side masks (L,U,R,D) bits 0..3, and internal pairings\n    uint8_t sideMask[8];\n    uint8_t pairCnt[8];\n    uint8_t pairs[8][2][2]; // up to 2 segments (each a pair of sides)\n\n    auto set1 = [&](int t, int a, int b, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 1;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = pairs[t][1][1] = 255;\n    };\n    auto set2 = [&](int t, int a, int b, int c, int d, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 2;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = (uint8_t)c;\n        pairs[t][1][1] = (uint8_t)d;\n    };\n\n    // 0: L-U\n    set1(0, 0, 1, (1u<<0) | (1u<<1));\n    // 1: L-D\n    set1(1, 0, 3, (1u<<0) | (1u<<3));\n    // 2: R-D\n    set1(2, 2, 3, (1u<<2) | (1u<<3));\n    // 3: U-R\n    set1(3, 1, 2, (1u<<1) | (1u<<2));\n    // 4: (L-U) and (R-D)\n    set2(4, 0, 1, 2, 3, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 5: (L-D) and (U-R)\n    set2(5, 0, 3, 1, 2, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 6: L-R\n    set1(6, 0, 2, (1u<<0) | (1u<<2));\n    // 7: U-D\n    set1(7, 1, 3, (1u<<1) | (1u<<3));\n\n    auto applyFromInit = [&](int idx, uint8_t r) -> uint8_t {\n        return rotStep[initState[idx]][r & 3];\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift64 rng(seed);\n\n    // Current state\n    vector<uint8_t> curRot(TILES, 0);\n    vector<uint8_t> curState(TILES, 0);\n    vector<uint8_t> curMask(TILES, 0);\n\n    // indices of 4/5 tiles (pairing-changing tiles)\n    vector<int> pairTiles;\n    pairTiles.reserve(TILES);\n    for (int p = 0; p < TILES; p++) {\n        if (initState[p] == 4 || initState[p] == 5) pairTiles.push_back(p);\n    }\n\n    // Random init\n    for (int p = 0; p < TILES; p++) {\n        uint8_t r = (uint8_t)rng.nextInt(0, 3);\n        curRot[p] = r;\n        curState[p] = applyFromInit(p, r);\n        curMask[p] = sideMask[curState[p]];\n    }\n\n    // Greedy init:\n    // - reward active-active matches\n    // - penalize mismatch\n    // - penalize boundary leaks\n    // - add pairing potential for 4/5 tiles (and generally for any tile's internal pairs)\n    auto cont = [&](int p, int side) -> int {\n        int i = p / N, j = p % N;\n        if (side == 0) { // L\n            if (j == 0) return 0;\n            return (curMask[p - 1] & (1u << 2)) ? 1 : 0;\n        } else if (side == 1) { // U\n            if (i == 0) return 0;\n            return (curMask[p - N] & (1u << 3)) ? 1 : 0;\n        } else if (side == 2) { // R\n            if (j == N - 1) return 0;\n            return (curMask[p + 1] & (1u << 0)) ? 1 : 0;\n        } else { // D\n            if (i == N - 1) return 0;\n            return (curMask[p + N] & (1u << 1)) ? 1 : 0;\n        }\n    };\n\n    auto greedyLocalScore = [&](int p, uint8_t stCand) -> int {\n        int i = p / N, j = p % N;\n        uint8_t mCand = sideMask[stCand];\n\n        int sc = 0;\n        // border match score: only active-active is good\n        auto evalSide = [&](int side, int ni, int nj, int oppSide) {\n            bool a = (mCand >> side) & 1;\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (a) sc -= 6; // boundary leak\n                return;\n            }\n            int q = ni * N + nj;\n            bool b = (curMask[q] >> oppSide) & 1;\n            if (a && b) sc += 5;\n            else if (a != b) sc -= 5;\n            // both inactive: 0\n        };\n\n        evalSide(0, i, j - 1, 2);\n        evalSide(1, i - 1, j, 3);\n        evalSide(2, i, j + 1, 0);\n        evalSide(3, i + 1, j, 1);\n\n        // internal pairing potential:\n        // prefer pairing that connects \"continuable\" sides together.\n        int c[4] = { cont(p,0), cont(p,1), cont(p,2), cont(p,3) };\n        int ps = 0;\n        for (int k = 0; k < pairCnt[stCand]; k++) {\n            int a = pairs[stCand][k][0], b = pairs[stCand][k][1];\n            ps += c[a] * c[b];\n        }\n        sc += ps * 3;\n\n        return sc;\n    };\n\n    vector<int> order(TILES);\n    iota(order.begin(), order.end(), 0);\n\n    for (int sweep = 0; sweep < 8; sweep++) {\n        for (int i = TILES - 1; i > 0; i--) {\n            int j = (int)(rng.nextU64() % (uint64_t)(i + 1));\n            swap(order[i], order[j]);\n        }\n        for (int idx = 0; idx < TILES; idx++) {\n            int p = order[idx];\n            int bestSc = INT_MIN;\n            uint8_t bestDelta = 0;\n            uint8_t base = curState[p];\n            for (uint8_t dlt = 0; dlt < 4; dlt++) {\n                uint8_t stCand = rotStep[base][dlt];\n                int sc = greedyLocalScore(p, stCand);\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestDelta = dlt;\n                }\n            }\n            if (bestDelta != 0) {\n                curRot[p] = (uint8_t)((curRot[p] + bestDelta) & 3);\n                curState[p] = rotStep[curState[p]][bestDelta];\n                curMask[p] = sideMask[curState[p]];\n            }\n        }\n    }\n\n    // Evaluation buffers\n    static int degArr[PORTS];\n    static int nb1[PORTS];\n    static int nb2[PORTS];\n    static uint8_t vis[PORTS];\n    static int stackBuf[PORTS];\n\n    auto addEdge = [&](int u, int v) {\n        int du = degArr[u]++;\n        if (du == 0) nb1[u] = v;\n        else nb2[u] = v;\n\n        int dv = degArr[v]++;\n        if (dv == 0) nb1[v] = u;\n        else nb2[v] = u;\n    };\n\n    auto evaluate = [&]() -> EvalResult {\n        memset(degArr, 0, sizeof(degArr));\n        memset(nb1, 0xFF, sizeof(nb1)); // -1\n        memset(nb2, 0xFF, sizeof(nb2));\n        memset(vis, 0, sizeof(vis));\n\n        // internal edges\n        for (int p = 0; p < TILES; p++) {\n            int base = p * 4;\n            uint8_t st = curState[p];\n            for (int k = 0; k < pairCnt[st]; k++) {\n                int a = pairs[st][k][0];\n                int b = pairs[st][k][1];\n                addEdge(base + a, base + b);\n            }\n        }\n\n        // external edges\n        int matchedEdges = 0;\n        // horizontal\n        for (int i = 0; i < N; i++) {\n            int row = i * N;\n            for (int j = 0; j < N - 1; j++) {\n                int p = row + j;\n                int q = p + 1;\n                if ((curMask[p] & (1u << 2)) && (curMask[q] & (1u << 0))) {\n                    addEdge(p * 4 + 2, q * 4 + 0);\n                    matchedEdges++;\n                }\n            }\n        }\n        // vertical\n        for (int i = 0; i < N - 1; i++) {\n            int row = i * N;\n            int row2 = (i + 1) * N;\n            for (int j = 0; j < N; j++) {\n                int p = row + j;\n                int q = row2 + j;\n                if ((curMask[p] & (1u << 3)) && (curMask[q] & (1u << 1))) {\n                    addEdge(p * 4 + 3, q * 4 + 1);\n                    matchedEdges++;\n                }\n            }\n        }\n\n        int openEnds = 0;\n        for (int u = 0; u < PORTS; u++) if (degArr[u] == 1) openEnds++;\n\n        int L1 = 0, L2 = 0;\n        int loopCount = 0;\n        int compCount = 0;\n        int largestCompLen = 0;\n        long long sumCompLenSq = 0;\n\n        for (int s = 0; s < PORTS; s++) {\n            if (degArr[s] == 0 || vis[s]) continue;\n            compCount++;\n\n            int top = 0;\n            stackBuf[top++] = s;\n            vis[s] = 1;\n\n            int compSize = 0;\n            bool isCycle = true;\n\n            while (top) {\n                int x = stackBuf[--top];\n                compSize++;\n                if (degArr[x] != 2) isCycle = false;\n\n                int a = nb1[x], b = nb2[x];\n                if (a != -1 && !vis[a]) { vis[a] = 1; stackBuf[top++] = a; }\n                if (b != -1 && !vis[b]) { vis[b] = 1; stackBuf[top++] = b; }\n            }\n\n            int compLen = compSize / 2; // moves\n            largestCompLen = max(largestCompLen, compLen);\n            sumCompLenSq += 1LL * compLen * compLen;\n\n            if (isCycle) {\n                loopCount++;\n                if (compLen > L1) { L2 = L1; L1 = compLen; }\n                else if (compLen > L2) { L2 = compLen; }\n            }\n        }\n\n        long long base = (loopCount >= 2) ? 1LL * L1 * L2 : 0LL;\n\n        // Energy:\n        // - if >=2 loops exist: focus on product, but discourage too many loops\n        // - if <2: grow large components (easy to close later) and reduce fragmentation\n        double energy;\n        if (loopCount >= 2) {\n            energy = base * 200.0\n                   + (L1 + L2) * 50.0\n                   + largestCompLen * 5.0\n                   + sumCompLenSq * 0.002\n                   - openEnds * 2.0\n                   - max(0, loopCount - 2) * 500.0;\n        } else if (loopCount == 1) {\n            energy = L1 * 60.0\n                   + largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 6000.0;\n        } else {\n            energy = largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 12000.0;\n        }\n\n        return EvalResult{base, L1, L2, loopCount, compCount, matchedEdges, openEnds,\n                          largestCompLen, sumCompLenSq, energy};\n    };\n\n    EvalResult curEval = evaluate();\n    long long bestBase = curEval.baseScore;\n    int bestTie = curEval.L1 + curEval.L2;\n    vector<uint8_t> bestRot = curRot;\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.93;\n\n    // SA temperature (energy scale is now larger)\n    const double T0 = 12000.0;\n    const double T1 = 150.0;\n\n    struct Backup {\n        int p;\n        uint8_t rot, st, mask;\n    };\n\n    auto applyDelta = [&](int p, uint8_t delta) {\n        if ((delta & 3) == 0) return;\n        curRot[p] = (uint8_t)((curRot[p] + delta) & 3);\n        curState[p] = rotStep[curState[p]][delta & 3];\n        curMask[p] = sideMask[curState[p]];\n    };\n\n    long long iter = 0;\n    while (true) {\n        iter++;\n        if ((iter & 1023) == 0) {\n            double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (sec >= TL) break;\n        }\n\n        // move type\n        int r = (int)(rng.nextU64() % 1000);\n\n        vector<int> ps;\n        vector<uint8_t> deltas;\n\n        if (r < 850) {\n            // single tile (bias to 4/5 tiles sometimes)\n            int p;\n            if (!pairTiles.empty() && rng.nextDouble() < 0.45) {\n                p = pairTiles[rng.nextInt(0, (int)pairTiles.size() - 1)];\n            } else {\n                p = (int)(rng.nextU64() % TILES);\n            }\n            uint8_t delta = (uint8_t)(1 + (rng.nextU32() % 3));\n            uint8_t newS = rotStep[curState[p]][delta];\n            if (newS == curState[p]) { delta = 1; }\n            ps = {p};\n            deltas = {delta};\n        } else if (r < 950) {\n            // 2x2 move\n            int i = rng.nextInt(0, N - 2);\n            int j = rng.nextInt(0, N - 2);\n            int p0 = i * N + j;\n            ps = {p0, p0 + 1, p0 + N, p0 + N + 1};\n            deltas.resize(4);\n            int nonzero = 0;\n            for (int k = 0; k < 4; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,3)] = 1;\n        } else {\n            // 1x3 or 3x1 move\n            bool horiz = (rng.nextU32() & 1);\n            if (horiz) {\n                int i = rng.nextInt(0, N - 1);\n                int j = rng.nextInt(0, N - 3);\n                int p0 = i * N + j;\n                ps = {p0, p0 + 1, p0 + 2};\n            } else {\n                int i = rng.nextInt(0, N - 3);\n                int j = rng.nextInt(0, N - 1);\n                int p0 = i * N + j;\n                ps = {p0, p0 + N, p0 + 2 * N};\n            }\n            deltas.resize(3);\n            int nonzero = 0;\n            for (int k = 0; k < 3; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,2)] = 1;\n        }\n\n        // backup and apply\n        vector<Backup> backups;\n        backups.reserve(ps.size());\n        for (int idx = 0; idx < (int)ps.size(); idx++) {\n            int p = ps[idx];\n            backups.push_back(Backup{p, curRot[p], curState[p], curMask[p]});\n            applyDelta(p, deltas[idx]);\n        }\n\n        EvalResult nxtEval = evaluate();\n\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = min(1.0, sec / TL);\n        double Temp = T0 * pow(T1 / T0, t);\n\n        double diff = nxtEval.energy - curEval.energy;\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else {\n            double prob = exp(diff / Temp);\n            accept = (rng.nextDouble() < prob);\n        }\n\n        if (accept) {\n            curEval = nxtEval;\n            // best by true score, tie by L1+L2\n            int tie = nxtEval.L1 + nxtEval.L2;\n            if (nxtEval.baseScore > bestBase || (nxtEval.baseScore == bestBase && tie > bestTie)) {\n                bestBase = nxtEval.baseScore;\n                bestTie = tie;\n                bestRot = curRot;\n            }\n        } else {\n            // revert\n            for (auto &b : backups) {\n                curRot[b.p] = b.rot;\n                curState[b.p] = b.st;\n                curMask[b.p] = b.mask;\n            }\n        }\n    }\n\n    // output best\n    string out;\n    out.reserve(TILES);\n    for (int p = 0; p < TILES; p++) out.push_back(char('0' + (bestRot[p] & 3)));\n    cout << out << \"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline int hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int bestAlmost = 0;\n    int edgesTotal = 0;\n    int cycleSurplus = 0;\n    int cyclicLargest = 0;\n    int borderOut = 0;\n    int mismatch = 0;\n    int treeMass = 0; // sum of squares of tree component sizes\n    long long obj = 0;\n};\n\nstruct UF {\n    int n;\n    int p[110], sz[110];\n    void init(int n_) {\n        n = n_;\n        for (int i = 0; i < n; i++) { p[i] = i; sz[i] = 1; }\n    }\n    int find(int a) {\n        while (p[a] != a) {\n            p[a] = p[p[a]];\n            a = p[a];\n        }\n        return a;\n    }\n    void unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return;\n        if (sz[a] < sz[b]) swap(a,b);\n        p[b] = a;\n        sz[a] += sz[b];\n    }\n};\n\nstruct Solver {\n    int N, T;\n    int NN;\n    int V; // N*N - 1\n    vector<uint8_t> init;\n    int initBlank = -1;\n\n    // blank move directions: U D L R\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char dch[4] = {'U','D','L','R'};\n    const int opp[4] = {1,0,3,2};\n\n    // precomputed legal moves from each blank cell\n    int moveCnt[110];\n    int moveList[110][4];\n\n    // edge storage for evaluation (max 2*N*(N-1) <= 180 for N=10)\n    int eU[256], eV[256];\n\n    void precompute_moves() {\n        for (int pos = 0; pos < NN; pos++) {\n            int r = pos / N, c = pos % N;\n            int k = 0;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    moveList[pos][k++] = d;\n                }\n            }\n            moveCnt[pos] = k;\n        }\n    }\n\n    inline void do_move_inplace(vector<uint8_t>& b, int& blank, int d) const {\n        int r = blank / N, c = blank % N;\n        int nb = (r + dr[d]) * N + (c + dc[d]);\n        swap(b[blank], b[nb]);\n        blank = nb;\n    }\n\n    Metrics evaluate(const vector<uint8_t>& b) {\n        UF uf;\n        uf.init(NN);\n\n        int eidx = 0;\n        int edgesTotal = 0;\n        int borderOut = 0;\n        int mismatch = 0;\n\n        // border penalties + adjacency processing (also union matches)\n        for (int r = 0; r < N; r++) {\n            int base = r * N;\n            for (int c = 0; c < N; c++) {\n                int id = base + c;\n                uint8_t t = b[id];\n                if (t == 0) continue;\n\n                if (r == 0 && (t & 2)) borderOut++;\n                if (r == N-1 && (t & 8)) borderOut++;\n                if (c == 0 && (t & 1)) borderOut++;\n                if (c == N-1 && (t & 4)) borderOut++;\n\n                // right neighbor\n                if (c + 1 < N) {\n                    int id2 = id + 1;\n                    uint8_t t2 = b[id2];\n                    bool ar = (t & 4);\n                    bool bl = (t2 & 1);\n                    // mismatch counts line-ends that do not match\n                    if (t != 0 && ar && !(t2 != 0 && bl)) mismatch++;\n                    if (t2 != 0 && bl && !(t != 0 && ar)) mismatch++;\n                    if (t2 != 0 && ar && bl) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n                // down neighbor\n                if (r + 1 < N) {\n                    int id2 = id + N;\n                    uint8_t t2 = b[id2];\n                    bool ad = (t & 8);\n                    bool bu = (t2 & 2);\n                    if (t != 0 && ad && !(t2 != 0 && bu)) mismatch++;\n                    if (t2 != 0 && bu && !(t != 0 && ad)) mismatch++;\n                    if (t2 != 0 && ad && bu) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n            }\n        }\n\n        static int vcnt[110];\n        static int ecnt[110];\n        for (int i = 0; i < NN; i++) { vcnt[i] = 0; ecnt[i] = 0; }\n\n        for (int i = 0; i < NN; i++) {\n            if (b[i] == 0) continue;\n            vcnt[uf.find(i)]++;\n        }\n        for (int k = 0; k < eidx; k++) {\n            int root = uf.find(eU[k]);\n            ecnt[root]++;\n        }\n\n        Metrics m;\n        m.edgesTotal = edgesTotal;\n        m.borderOut = borderOut;\n        m.mismatch = mismatch;\n\n        int largestTree = 0;\n        int bestAlmost = 0;\n        int cycleSurplus = 0;\n        int cyclicLargest = 0;\n        long long treeMass = 0;\n\n        for (int i = 0; i < NN; i++) {\n            int Vc = vcnt[i];\n            if (Vc == 0) continue;\n            int Ec = ecnt[i];\n            int extra = max(0, Ec - (Vc - 1));\n            cycleSurplus += extra;\n            if (extra > 0) cyclicLargest = max(cyclicLargest, Vc);\n\n            if (extra == 0) {\n                largestTree = max(largestTree, Vc);\n                treeMass += 1LL * Vc * Vc;\n            }\n            // closeness-to-tree potential (penalize extra edges strongly)\n            bestAlmost = max(bestAlmost, Vc - 10 * extra);\n        }\n\n        m.largestTree = largestTree;\n        m.bestAlmost = bestAlmost;\n        m.cycleSurplus = cycleSurplus;\n        m.cyclicLargest = cyclicLargest;\n        m.treeMass = (int)min<long long>(treeMass, INT_MAX);\n\n        // Objective: prioritize real largest-tree size, then push away from cycles,\n        // and encourage border/port consistency.\n        long long obj = 0;\n        obj += 1000000000LL * m.largestTree;          // primary\n        obj += 20000000LL   * m.bestAlmost;           // secondary\n        obj += 5000LL       * m.treeMass;             // encourage big forests\n        obj += 200000LL     * m.edgesTotal;           // matched edges help (but not at all costs)\n        obj -= 50000000LL   * m.cyclicLargest;        // big cyclic component is disastrous\n        obj -= 20000000LL   * m.cycleSurplus;         // cycles are bad\n        obj -= 500000LL     * m.borderOut;            // outward ports cannot be matched\n        obj -= 20000LL      * m.mismatch;             // unmatched ends hurt\n\n        m.obj = obj;\n        return m;\n    }\n\n    struct RunResult {\n        string path;\n        int bestS;\n        int bestLen;\n    };\n\n    RunResult run_once(XorShift64& rng, double time_frac) {\n        vector<uint8_t> b = init;\n        int blank = initBlank;\n\n        Metrics cur = evaluate(b);\n        int bestS = cur.largestTree;\n        int bestLen = 0;\n        string path;\n        path.reserve(T);\n\n        int prevd = -1;\n\n        // exploration schedule (vary per run)\n        double eps0 = 0.40 - 0.15 * time_frac; // earlier runs explore more\n        double eps1 = 0.05;\n        // randomize slightly per run\n        eps0 *= (0.85 + 0.30 * rng.next_double());\n        eps1 *= (0.85 + 0.30 * rng.next_double());\n        eps0 = min(0.65, max(0.05, eps0));\n        eps1 = min(0.20, max(0.01, eps1));\n\n        for (int step = 0; step < T; step++) {\n            // build candidate moves from precomputed list\n            int cand[4], cc = 0;\n            int mc = moveCnt[blank];\n            for (int i = 0; i < mc; i++) cand[cc++] = moveList[blank][i];\n\n            // avoid immediate reverse most of the time (but not always)\n            if (prevd != -1 && cc >= 2 && rng.next_double() < 0.90) {\n                int rev = opp[prevd];\n                int nc = 0;\n                for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                if (nc >= 1) cc = nc;\n            }\n\n            struct CandInfo { int d; Metrics m1; long long score; };\n            CandInfo infos[4];\n\n            // evaluate each candidate (1-step)\n            for (int i = 0; i < cc; i++) {\n                int d = cand[i];\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d);\n                Metrics m1 = evaluate(b);\n                // revert\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                infos[i] = {d, m1, m1.obj};\n            }\n\n            // take top-2 by score and do 2-step lookahead on them\n            int order[4];\n            iota(order, order + cc, 0);\n            sort(order, order + cc, [&](int a, int b) {\n                return infos[a].score > infos[b].score;\n            });\n\n            int topk = min(2, cc);\n            for (int t = 0; t < topk; t++) {\n                int idx = order[t];\n                int d1 = infos[idx].d;\n\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d1);\n\n                // enumerate next moves excluding immediate reverse of d1\n                long long best2 = LLONG_MIN;\n                int mc2 = moveCnt[blank];\n                for (int j = 0; j < mc2; j++) {\n                    int d2 = moveList[blank][j];\n                    if (d2 == opp[d1] && mc2 >= 2) continue;\n                    int savedBlank2 = blank;\n                    do_move_inplace(b, blank, d2);\n                    Metrics m2 = evaluate(b);\n                    best2 = max(best2, m2.obj);\n                    // revert\n                    swap(b[savedBlank2], b[blank]);\n                    blank = savedBlank2;\n                }\n\n                // revert state1\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                if (best2 != LLONG_MIN) {\n                    // small influence of lookahead\n                    infos[idx].score = infos[idx].m1.obj + best2 / 10;\n                }\n            }\n\n            // epsilon-greedy choice\n            double eps = eps0 + (eps1 - eps0) * (double)step / max(1, T - 1);\n            int chosen = 0;\n            if (rng.next_double() < eps) {\n                chosen = rng.next_int(0, cc - 1);\n            } else {\n                long long bestScore = LLONG_MIN;\n                for (int i = 0; i < cc; i++) {\n                    // small random tie-break\n                    long long s = infos[i].score + (long long)(rng.next_u64() & 1023ULL);\n                    if (s > bestScore) {\n                        bestScore = s;\n                        chosen = i;\n                    }\n                }\n            }\n\n            int d = infos[chosen].d;\n            do_move_inplace(b, blank, d);\n            path.push_back(dch[d]);\n            prevd = d;\n            cur = infos[chosen].m1;\n\n            int S = cur.largestTree;\n            int len = step + 1;\n            if (S > bestS) {\n                bestS = S;\n                bestLen = len;\n            } else if (S == bestS) {\n                // if perfect, prefer shorter; otherwise shorter is fine too\n                if (len < bestLen) bestLen = len;\n            }\n\n            if (bestS == V) {\n                // first time reaching perfect is already shortest in this run\n                bestLen = len;\n                break;\n            }\n        }\n\n        RunResult rr;\n        rr.bestS = bestS;\n        rr.bestLen = bestLen;\n        rr.path = path.substr(0, bestLen);\n        return rr;\n    }\n\n    string solve() {\n        NN = N * N;\n        V = NN - 1;\n        precompute_moves();\n\n        Metrics m0 = evaluate(init);\n        int globalBestS = m0.largestTree;\n        int globalBestLen = 0;\n        string globalBest = \"\";\n\n        auto st = chrono::high_resolution_clock::now();\n        const double TL = 2.85;\n\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        while (true) {\n            auto now = chrono::high_resolution_clock::now();\n            double elapsed = chrono::duration<double>(now - st).count();\n            if (elapsed >= TL) break;\n\n            double frac = elapsed / TL;\n            RunResult rr = run_once(rng, frac);\n\n            if (rr.bestS > globalBestS) {\n                globalBestS = rr.bestS;\n                globalBestLen = rr.bestLen;\n                globalBest = rr.path;\n            } else if (rr.bestS == globalBestS) {\n                // if perfect, shorter is strictly better; otherwise doesn't affect score, but keep shorter\n                if (rr.bestLen < globalBestLen) {\n                    globalBestLen = rr.bestLen;\n                    globalBest = rr.path;\n                }\n            }\n\n            if (globalBestS == V && globalBestLen == 0) break;\n        }\n\n        if ((int)globalBest.size() > T) globalBest.resize(T);\n        return globalBest;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.T;\n    int N = solver.N;\n\n    solver.init.assign(N * N, 0);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) {\n            int v = hexval(s[j]);\n            solver.init[i * N + j] = (uint8_t)v;\n            if (v == 0) solver.initBlank = i * N + j;\n        }\n    }\n\n    string ans = solver.solve();\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int R = 10000;\nstatic constexpr long long LEN = 100000000LL; // 1e8: endpoints well within 1e9\n\n// ---------------- RNG ----------------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline double uniform01() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double uniform(double lo, double hi) {\n        return lo + (hi - lo) * uniform01();\n    }\n    inline int uniformInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// ---------------- Geometry / signature ----------------\nstruct Point {\n    int x, y;\n};\n\nstruct Line {\n    // parameters\n    double theta; // [0, pi)\n    double u;     // signed offset along normal\n    // integer endpoints for exact side test\n    long long px, py, qx, qy;\n};\n\nstruct Key {\n    uint64_t lo = 0, hi = 0; // support up to 128 cuts\n    bool operator==(Key const& o) const noexcept { return lo == o.lo && hi == o.hi; }\n};\n\nstruct KeyHash {\n    size_t operator()(Key const& k) const noexcept {\n        uint64_t h = k.lo ^ splitmix64(k.hi + 0x9e3779b97f4a7c15ULL);\n        return (size_t)splitmix64(h);\n    }\n};\n\nstatic inline int getBit(const Key& k, int idx) {\n    if (idx < 64) return (int)((k.lo >> idx) & 1ULL);\n    return (int)((k.hi >> (idx - 64)) & 1ULL);\n}\nstatic inline void setBit(Key& k, int idx) {\n    if (idx < 64) k.lo |= (1ULL << idx);\n    else k.hi |= (1ULL << (idx - 64));\n}\nstatic inline void toggleBit(Key& k, int idx) {\n    if (idx < 64) k.lo ^= (1ULL << idx);\n    else k.hi ^= (1ULL << (idx - 64));\n}\n\nstatic inline double wrapTheta(double th) {\n    const double PI = acos(-1.0);\n    while (th < 0) th += PI;\n    while (th >= PI) th -= PI;\n    return th;\n}\n\nstatic inline Line buildLine(double theta, double u) {\n    // normal n=(cos, sin), direction t=(-sin, cos)\n    double cs = cos(theta), sn = sin(theta);\n    double tx = -sn, ty = cs;\n    double cx = u * cs, cy = u * sn;\n\n    long double px = (long double)cx + (long double)LEN * (long double)tx;\n    long double py = (long double)cy + (long double)LEN * (long double)ty;\n    long double qx = (long double)cx - (long double)LEN * (long double)tx;\n    long double qy = (long double)cy - (long double)LEN * (long double)ty;\n\n    Line L;\n    L.theta = theta;\n    L.u = u;\n    L.px = llround(px);\n    L.py = llround(py);\n    L.qx = llround(qx);\n    L.qy = llround(qy);\n    if (L.px == L.qx && L.py == L.qy) L.qx += 1; // extremely unlikely\n    return L;\n}\n\n// side test using exact integer cross product\n// returns 1 if cross>0, 0 if cross<0, -1 if cross==0 (strawberry disappears; we avoid)\nstatic inline int sideBit(const Line& L, const Point& p) {\n    __int128 dx = (__int128)L.qx - (__int128)L.px;\n    __int128 dy = (__int128)L.qy - (__int128)L.py;\n    __int128 ax = (__int128)p.x - (__int128)L.px;\n    __int128 ay = (__int128)p.y - (__int128)L.py;\n    __int128 cr = dx * ay - dy * ax;\n    if (cr > 0) return 1;\n    if (cr < 0) return 0;\n    return -1;\n}\n\nstatic inline bool lineHitsAnyPoint(const Line& L, const vector<Point>& pts) {\n    for (auto& p : pts) if (sideBit(L, p) == -1) return true;\n    return false;\n}\n\n// ---------------- State with incremental updates ----------------\nstruct State {\n    int N = 0;\n    int L = 0;\n    vector<Point> pts;\n    vector<Line> lines;\n\n    vector<Key> sig; // per point signature\n    boost::unordered_flat_map<Key, int, KeyHash> mp; // region signature -> count\n\n    array<int, 11> a{}; // demands 1..10\n    array<int, 11> b{}; // b[d] = number of regions with exactly d strawberries, d=1..10\n\n    long long excess = 0;   // sum max(0, c-10)\n    long long excess2 = 0;  // sum max(0, c-10)^2\n    int goodPieces = 0;     // number of regions with 1..10 strawberries\n\n    void clearCounts() {\n        mp.clear();\n        b.fill(0);\n        excess = 0;\n        excess2 = 0;\n        goodPieces = 0;\n    }\n\n    static inline long long contribExcess(int c) {\n        if (c <= 10) return 0;\n        return (long long)(c - 10);\n    }\n    static inline long long contribExcess2(int c) {\n        if (c <= 10) return 0;\n        long long e = (long long)(c - 10);\n        return e * e;\n    }\n\n    inline void updateMetrics(int oldC, int newC) {\n        if (1 <= oldC && oldC <= 10) { b[oldC]--; goodPieces--; }\n        if (1 <= newC && newC <= 10) { b[newC]++; goodPieces++; }\n\n        excess -= contribExcess(oldC);\n        excess += contribExcess(newC);\n\n        excess2 -= contribExcess2(oldC);\n        excess2 += contribExcess2(newC);\n    }\n\n    inline void incRegion(const Key& k) {\n        auto it = mp.find(k);\n        if (it == mp.end()) {\n            updateMetrics(0, 1);\n            mp.emplace(k, 1);\n        } else {\n            int oldC = it->second;\n            int newC = oldC + 1;\n            updateMetrics(oldC, newC);\n            it->second = newC;\n        }\n    }\n\n    inline void decRegion(const Key& k) {\n        auto it = mp.find(k);\n        int oldC = it->second;\n        int newC = oldC - 1;\n        updateMetrics(oldC, newC);\n        if (newC == 0) mp.erase(it);\n        else it->second = newC;\n    }\n\n    inline int distributed() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], b[d]);\n        return s;\n    }\n\n    inline long long deficit2() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - b[d]);\n            s += 1LL * def * def;\n        }\n        return s;\n    }\n\n    inline int overProduction() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += max(0, b[d] - a[d]);\n        return s;\n    }\n\n    inline long long energy() const {\n        // Goal: maximize distributed pieces.\n        // Secondary guidance:\n        // - Strongly reduce large pieces via excess2 (splitting 30 -> 15+15 helps).\n        // - Reduce deficit2 to guide toward matching each size count.\n        // - Mildly penalize overproduction (optional; very small).\n        // - Mildly reward having more 1..10 pieces (goodPieces).\n        int D = distributed();\n        long long def2 = deficit2();\n        int over = overProduction();\n\n        // Tuned scales:\n        // D changes by 1 is ~200k. Penalties are sized to matter but not dominate.\n        long long E = 0;\n        E += 1LL * D * 200000;\n        E += 1LL * goodPieces * 80;\n        E -= 1LL * excess2 * 2;\n        E -= 1LL * excess * 250;\n        E -= 1LL * def2 * 400;\n        E -= 1LL * over * 20;\n        return E;\n    }\n\n    bool buildInitialSignatures() {\n        sig.assign(N, Key{0, 0});\n        clearCounts();\n        mp.reserve((size_t)N * 2 + 64);\n\n        for (int i = 0; i < L; i++) {\n            for (int j = 0; j < N; j++) {\n                int sb = sideBit(lines[i], pts[j]);\n                if (sb == -1) return false;\n                if (sb == 1) setBit(sig[j], i);\n            }\n        }\n        for (int j = 0; j < N; j++) incRegion(sig[j]);\n        return true;\n    }\n\n    // replace one line and update incrementally; return false if invalid (hits a point), rolling back.\n    bool applyReplaceLine(int idx, const Line& newLine,\n                          vector<int>& changedIdx, vector<Key>& oldSig) {\n        changedIdx.clear();\n        oldSig.clear();\n        changedIdx.reserve(256);\n        oldSig.reserve(256);\n\n        for (int j = 0; j < N; j++) {\n            int nb = sideBit(newLine, pts[j]);\n            if (nb == -1) {\n                // rollback\n                for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n                    int pj = changedIdx[t];\n                    Key os = oldSig[t];\n                    Key cs = sig[pj];\n                    decRegion(cs);\n                    incRegion(os);\n                    sig[pj] = os;\n                }\n                changedIdx.clear();\n                oldSig.clear();\n                return false;\n            }\n            int ob = getBit(sig[j], idx);\n            if (nb == ob) continue;\n\n            changedIdx.push_back(j);\n            oldSig.push_back(sig[j]);\n\n            Key ns = sig[j];\n            toggleBit(ns, idx);\n            decRegion(sig[j]);\n            incRegion(ns);\n            sig[j] = ns;\n        }\n        return true;\n    }\n\n    void rollbackReplaceLine(const vector<int>& changedIdx, const vector<Key>& oldSig) {\n        for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n            int j = changedIdx[t];\n            Key os = oldSig[t];\n            Key cs = sig[j];\n            decRegion(cs);\n            incRegion(os);\n            sig[j] = os;\n        }\n    }\n};\n\n// ---------------- Timer ----------------\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// ---------------- Initialization / Moves ----------------\nstatic Line randomLineAnchored(RNG& rng, const vector<Point>& pts, double theta = -1.0, double noiseU = 800.0) {\n    const double PI = acos(-1.0);\n    if (theta < 0) theta = rng.uniform(0.0, PI);\n\n    double cs = cos(theta), sn = sin(theta);\n    const Point& p = pts[rng.uniformInt(0, (int)pts.size() - 1)];\n    double proj = cs * (double)p.x + sn * (double)p.y;\n\n    double u = proj + rng.uniform(-noiseU, noiseU);\n    double lim = R * 0.98;\n    u = max(-lim, min(lim, u));\n    return buildLine(theta, u);\n}\n\nstatic int nearestLineIndex(const vector<Line>& lines, const Point& p) {\n    int best = 0;\n    double bestAbs = 1e100;\n    for (int i = 0; i < (int)lines.size(); i++) {\n        double cs = cos(lines[i].theta), sn = sin(lines[i].theta);\n        double dist = cs * (double)p.x + sn * (double)p.y - lines[i].u;\n        double ad = fabs(dist);\n        if (ad < bestAbs) {\n            bestAbs = ad;\n            best = i;\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n    array<int, 11> a{};\n    for (int d = 1; d <= 10; d++) cin >> a[d];\n\n    vector<Point> pts(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 2.90;\n    const int L = 100; // always use all cuts\n\n    long long globalBestE = LLONG_MIN;\n    int globalBestD = -1;\n    vector<Line> globalBestLines;\n\n    // Multiple restarts\n    const int RESTARTS = 3;\n\n    for (int rs = 0; rs < RESTARTS; rs++) {\n        if (timer.elapsedSec() >= TIME_LIMIT) break;\n\n        double rem = TIME_LIMIT - timer.elapsedSec();\n        double budget = rem / (double)(RESTARTS - rs);\n\n        State st;\n        st.N = N;\n        st.L = L;\n        st.pts = pts;\n        st.a = a;\n        st.lines.resize(L);\n\n        // Structured-ish init: spread angles, random u near random point projections.\n        const double PI = acos(-1.0);\n        for (int i = 0; i < L; i++) {\n            double thetaBase = PI * (i + 0.5) / (double)L;\n            for (int tries = 0; tries < 2000; tries++) {\n                double theta = wrapTheta(thetaBase + rng.uniform(-0.03, 0.03));\n                Line ln = randomLineAnchored(rng, pts, theta, 1200.0);\n                if (!lineHitsAnyPoint(ln, pts)) { st.lines[i] = ln; break; }\n                if (tries == 1999) st.lines[i] = ln; // fallback (still likely ok)\n            }\n        }\n\n        if (!st.buildInitialSignatures()) {\n            // rare: regenerate trivially as 0 cuts\n            continue;\n        }\n\n        long long curE = st.energy();\n        int curD = st.distributed();\n\n        long long bestE = curE;\n        int bestD = curD;\n        vector<Line> bestLines = st.lines;\n\n        vector<int> changedIdx;\n        vector<Key> oldSig;\n\n        auto start = chrono::steady_clock::now();\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed >= budget) break;\n\n            double prog = elapsed / budget;\n\n            // Energy scale is around ~1e8, so temperatures should be ~1e5-1e6.\n            double T0 = 400000.0;\n            double T1 = 20000.0;\n            double T = T0 * (1.0 - prog) + T1 * prog;\n\n            // Focus selection: try to find a point in a too-large region.\n            int focusJ = rng.uniformInt(0, N - 1);\n            int focusCnt = 0;\n            if (rng.uniform01() < 0.45) {\n                int bestJ = focusJ;\n                int bestCnt = 0;\n                for (int t = 0; t < 15; t++) {\n                    int j = rng.uniformInt(0, N - 1);\n                    auto it = st.mp.find(st.sig[j]);\n                    int c = (it == st.mp.end()) ? 0 : it->second;\n                    if (c > bestCnt) { bestCnt = c; bestJ = j; }\n                }\n                focusJ = bestJ;\n                focusCnt = bestCnt;\n            } else {\n                auto it = st.mp.find(st.sig[focusJ]);\n                focusCnt = (it == st.mp.end()) ? 0 : it->second;\n            }\n\n            int idx;\n            bool focusMove = (focusCnt > 10 && rng.uniform01() < 0.70);\n            if (focusMove) idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n            else idx = rng.uniformInt(0, L - 1);\n\n            Line oldLine = st.lines[idx];\n            Line cand = oldLine;\n\n            double r = rng.uniform01();\n            if (focusMove || r < 0.25) {\n                // (Re)sample a line near the focus point to split large regions\n                double theta = rng.uniform(0.0, PI);\n                double cs = cos(theta), sn = sin(theta);\n                const Point& p = st.pts[focusJ];\n                double proj = cs * (double)p.x + sn * (double)p.y;\n                double u = proj + rng.uniform(-600.0, 600.0);\n                double lim = R * 0.98;\n                u = max(-lim, min(lim, u));\n                cand = buildLine(theta, u);\n            } else if (r < 0.70) {\n                // small perturb of both theta and u\n                double angleScale = 0.50 * (1.0 - prog) + 0.015;\n                double uScale = 4500.0 * (1.0 - prog) + 150.0;\n                cand.theta = wrapTheta(cand.theta + rng.uniform(-angleScale, angleScale));\n                cand.u += rng.uniform(-uScale, uScale);\n                double lim = R * 0.98;\n                cand.u = max(-lim, min(lim, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            } else {\n                // adjust only u to pass near some point (fine tuning)\n                int j = rng.uniformInt(0, N - 1);\n                double cs = cos(cand.theta), sn = sin(cand.theta);\n                double proj = cs * (double)st.pts[j].x + sn * (double)st.pts[j].y;\n                cand.u = proj + rng.uniform(-500.0, 500.0);\n                double lim = R * 0.98;\n                cand.u = max(-lim, min(lim, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            }\n\n            long long oldE = curE;\n            int oldD = curD;\n\n            if (!st.applyReplaceLine(idx, cand, changedIdx, oldSig)) continue;\n\n            long long newE = st.energy();\n            int newD = st.distributed();\n\n            long long delta = newE - oldE;\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / T;\n                if (x > -50) { // avoid underflow\n                    double prob = exp(x);\n                    if (rng.uniform01() < prob) accept = true;\n                }\n            }\n\n            if (accept) {\n                st.lines[idx] = cand;\n                curE = newE;\n                curD = newD;\n\n                if (curD > bestD || (curD == bestD && curE > bestE)) {\n                    bestD = curD;\n                    bestE = curE;\n                    bestLines = st.lines;\n                }\n            } else {\n                st.rollbackReplaceLine(changedIdx, oldSig);\n                curE = oldE;\n                curD = oldD;\n            }\n        }\n\n        if (bestD > globalBestD || (bestD == globalBestD && bestE > globalBestE)) {\n            globalBestD = bestD;\n            globalBestE = bestE;\n            globalBestLines = bestLines;\n        }\n    }\n\n    if (globalBestLines.empty()) {\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n    cout << (int)globalBestLines.size() << \"\\n\";\n    for (auto& Lx : globalBestLines) {\n        cout << Lx.px << \" \" << Lx.py << \" \" << Lx.qx << \" \" << Lx.qy << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    explicit XorShift(uint64_t seed = 0) { x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstatic inline uint64_t maskRange64(int l, int r) {\n    if (l > r) return 0;\n    uint64_t left = (~0ULL) << l;\n    uint64_t right = (r == 63) ? ~0ULL : ((1ULL << (r + 1)) - 1ULL);\n    return left & right;\n}\n\nstruct Bits128 {\n    uint64_t lo = 0, hi = 0;\n    inline void set(int idx) {\n        if (idx < 64) lo |= 1ULL << idx;\n        else hi |= 1ULL << (idx - 64);\n    }\n    inline bool test(int idx) const {\n        if (idx < 64) return (lo >> idx) & 1ULL;\n        else return (hi >> (idx - 64)) & 1ULL;\n    }\n    inline void reset(int idx) {\n        if (idx < 64) lo &= ~(1ULL << idx);\n        else hi &= ~(1ULL << (idx - 64));\n    }\n    inline bool any() const { return lo || hi; }\n    inline Bits128 operator&(const Bits128& o) const { return Bits128{lo & o.lo, hi & o.hi}; }\n\n    inline bool anyInRange(int l, int r) const {\n        if (l > r) return false;\n        uint64_t mlo = 0, mhi = 0;\n        if (l < 64) {\n            int rr = min(r, 63);\n            mlo = maskRange64(l, rr);\n        }\n        if (r >= 64) {\n            int ll = max(l, 64) - 64;\n            int rr = r - 64;\n            mhi = maskRange64(ll, rr);\n        }\n        return (lo & mlo) || (hi & mhi);\n    }\n    inline int popcount() const { return __builtin_popcountll(lo) + __builtin_popcountll(hi); }\n};\n\nstruct Point { int x, y; };\n\nstruct Move {\n    Point p1, p2, p3, p4;\n    bool isAxis = true;\n    double val = -1e100;\n};\n\nstruct Params {\n    int topP = 220;\n    int midP = 900;\n    int randP = 60;\n    double noise = 0.02;\n\n    // normal mode (progressive)\n    double alphaStart = 0.55, alphaEnd = 0.28;     // perimeter penalty\n    double betaStart  = 2.00, betaEnd  = 0.60;     // connectivity bonus\n\n    // fill fallback\n    double fillAlpha = 0.85;\n    double fillBeta  = 1.20;\n    double fillWeightCoef = 0.20;\n};\n\nstruct State {\n    int N;\n    int shiftV;           // N-1\n    int U, V;             // 2N-1\n\n    array<uint64_t, 61> dotRow{}; // y -> bits x\n    array<uint64_t, 61> dotCol{}; // x -> bits y\n\n    vector<Bits128> diagVdots; // vIdx -> bits u\n    vector<Bits128> antiUdots; // u -> bits vIdx\n\n    array<uint64_t, 61> hUsed{}; // y -> bits x seg (x,y)-(x+1,y)\n    array<uint64_t, 61> vUsed{}; // x -> bits y seg (x,y)-(x,y+1)\n\n    // diagonal segment usage as bitmasks per line:\n    // d1: slope +1, indexed by vIdx = x-y+shiftV, bit = position along that diagonal\n    // d2: slope -1, indexed by u = x+y, bit = position along that anti-diagonal\n    vector<uint64_t> d1SegUsed; // size V\n    vector<uint64_t> d2SegUsed; // size U\n\n    array<uint8_t, 61> rowCnt{};\n    array<uint8_t, 61> colCnt{};\n    vector<uint8_t> diagVCnt;\n    vector<uint8_t> antiUCnt;\n\n    int dots = 0;\n    long long sumW = 0;\n\n    State(int N_=0): N(N_) {}\n\n    inline bool hasDot(int x, int y) const { return (dotRow[y] >> x) & 1ULL; }\n\n    inline void addDot(int x, int y) {\n        dotRow[y] |= 1ULL << x;\n        dotCol[x] |= 1ULL << y;\n        rowCnt[y]++; colCnt[x]++;\n        int u = x + y;\n        int vIdx = x - y + shiftV;\n        diagVdots[vIdx].set(u);\n        antiUdots[u].set(vIdx);\n        diagVCnt[vIdx]++; antiUCnt[u]++;\n        dots++;\n    }\n\n    inline bool rowHasDotBetween(int y, int x1, int x2) const {\n        int l = min(x1, x2) + 1;\n        int r = max(x1, x2) - 1;\n        if (l > r) return false;\n        return (dotRow[y] & maskRange64(l, r)) != 0;\n    }\n    inline bool colHasDotBetween(int x, int y1, int y2) const {\n        int l = min(y1, y2) + 1;\n        int r = max(y1, y2) - 1;\n        if (l > r) return false;\n        return (dotCol[x] & maskRange64(l, r)) != 0;\n    }\n    inline uint64_t segMaskX(int x1, int x2) const {\n        int l = min(x1, x2);\n        int r = max(x1, x2) - 1;\n        return maskRange64(l, r);\n    }\n    inline uint64_t segMaskY(int y1, int y2) const {\n        int l = min(y1, y2);\n        int r = max(y1, y2) - 1;\n        return maskRange64(l, r);\n    }\n\n    // diagonal line lengths (number of points)\n    inline int lenD1(int vIdx) const {\n        int d = vIdx - shiftV;\n        return N - abs(d);\n    }\n    inline int lenD2(int u) const {\n        return N - abs(u - (N - 1));\n    }\n\n    inline int posD1(int vIdx, int x, int y) const {\n        int d = vIdx - shiftV;\n        // start is (d,0) if d>=0 else (0,-d)\n        // along line, (x,y) increases together; position equals y if d>=0 else x\n        return (d >= 0) ? y : x;\n    }\n    inline int posD2(int u, int x, int y) const {\n        int startX = (u < N) ? 0 : (u - (N - 1));\n        (void)y;\n        return x - startX;\n    }\n\n    inline bool d1FreeRange(int vIdx, int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return true;\n        uint64_t m = maskRange64(l, r);\n        return (d1SegUsed[vIdx] & m) == 0;\n    }\n    inline bool d2FreeRange(int u, int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return true;\n        uint64_t m = maskRange64(l, r);\n        return (d2SegUsed[u] & m) == 0;\n    }\n    inline void d1MarkRange(int vIdx, int posA, int posB) {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return;\n        d1SegUsed[vIdx] |= maskRange64(l, r);\n    }\n    inline void d2MarkRange(int u, int posA, int posB) {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return;\n        d2SegUsed[u] |= maskRange64(l, r);\n    }\n\n    inline Point uvToXY(int u, int vIdx) const {\n        int v = vIdx - shiftV;\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    inline bool canAxisRect(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 || y1 == y2) return false;\n        if (hasDot(x1, y1)) return false;\n        if (!hasDot(x2, y1) || !hasDot(x2, y2) || !hasDot(x1, y2)) return false;\n\n        if (rowHasDotBetween(y1, x1, x2)) return false;\n        if (rowHasDotBetween(y2, x1, x2)) return false;\n        if (colHasDotBetween(x1, y1, y2)) return false;\n        if (colHasDotBetween(x2, y1, y2)) return false;\n\n        uint64_t hm = segMaskX(x1, x2);\n        if ((hUsed[y1] & hm) || (hUsed[y2] & hm)) return false;\n        uint64_t vm = segMaskY(y1, y2);\n        if ((vUsed[x1] & vm) || (vUsed[x2] & vm)) return false;\n\n        return true;\n    }\n\n    inline void applyAxisRect(const Move& mv) {\n        int x1 = mv.p1.x, y1 = mv.p1.y;\n        int x2 = mv.p2.x, y2 = mv.p3.y;\n\n        uint64_t hm = segMaskX(x1, x2);\n        hUsed[y1] |= hm;\n        hUsed[y2] |= hm;\n        uint64_t vm = segMaskY(y1, y2);\n        vUsed[x1] |= vm;\n        vUsed[x2] |= vm;\n\n        addDot(x1, y1);\n    }\n\n    inline bool canDiagRect(int x1, int y1, int u2, int v2Idx) const {\n        if (hasDot(x1, y1)) return false;\n        int u1 = x1 + y1;\n        int v1Idx = x1 - y1 + shiftV;\n\n        // condition 2: no dots on perimeter in (u,v) space\n        if (diagVdots[v1Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (diagVdots[v2Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (antiUdots[u1].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n        if (antiUdots[u2].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n\n        Point p1 = {x1, y1};\n        Point p2 = uvToXY(u2, v1Idx);\n        Point p3 = uvToXY(u2, v2Idx);\n        Point p4 = uvToXY(u1, v2Idx);\n\n        auto in = [&](Point p) { return 0 <= p.x && p.x < N && 0 <= p.y && p.y < N; };\n        if (!in(p2) || !in(p3) || !in(p4)) return false;\n        if (!hasDot(p2.x, p2.y) || !hasDot(p3.x, p3.y) || !hasDot(p4.x, p4.y)) return false;\n\n        // condition 3: no shared segments with existing diagonal segments\n        // edges: p1-p2 and p3-p4 are on d1 (v fixed); p2-p3 and p4-p1 are on d2 (u fixed)\n        int v1 = v1Idx;\n        int v2 = v2Idx;\n\n        int pos1_v1 = posD1(v1, p1.x, p1.y);\n        int pos2_v1 = posD1(v1, p2.x, p2.y);\n        if (!d1FreeRange(v1, pos1_v1, pos2_v1)) return false;\n\n        int pos3_v2 = posD1(v2, p3.x, p3.y);\n        int pos4_v2 = posD1(v2, p4.x, p4.y);\n        if (!d1FreeRange(v2, pos3_v2, pos4_v2)) return false;\n\n        int uA = u2;\n        int pos2_u2 = posD2(uA, p2.x, p2.y);\n        int pos3_u2 = posD2(uA, p3.x, p3.y);\n        if (!d2FreeRange(uA, pos2_u2, pos3_u2)) return false;\n\n        int uB = u1;\n        int pos4_u1 = posD2(uB, p4.x, p4.y);\n        int pos1_u1 = posD2(uB, p1.x, p1.y);\n        if (!d2FreeRange(uB, pos4_u1, pos1_u1)) return false;\n\n        return true;\n    }\n\n    inline void applyDiagRect(const Move& mv) {\n        // mark segments on corresponding diagonal lines\n        int u1 = mv.p1.x + mv.p1.y;\n        int u2 = mv.p2.x + mv.p2.y;\n        int v1 = mv.p1.x - mv.p1.y + shiftV;\n        int v2 = mv.p3.x - mv.p3.y + shiftV;\n\n        // p1-p2 on d1(v1)\n        d1MarkRange(v1, posD1(v1, mv.p1.x, mv.p1.y), posD1(v1, mv.p2.x, mv.p2.y));\n        // p2-p3 on d2(u2)\n        d2MarkRange(u2, posD2(u2, mv.p2.x, mv.p2.y), posD2(u2, mv.p3.x, mv.p3.y));\n        // p3-p4 on d1(v2)\n        d1MarkRange(v2, posD1(v2, mv.p3.x, mv.p3.y), posD1(v2, mv.p4.x, mv.p4.y));\n        // p4-p1 on d2(u1)\n        d2MarkRange(u1, posD2(u1, mv.p4.x, mv.p4.y), posD2(u1, mv.p1.x, mv.p1.y));\n\n        addDot(mv.p1.x, mv.p1.y);\n    }\n};\n\nstruct Result {\n    vector<array<int, 8>> ops;\n    long long sumW = 0;\n    int dots = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int c = (N - 1) / 2;\n\n    vector<vector<int>> w(N, vector<int>(N, 0)); // w[x][y]\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) {\n        int dx = x - c, dy = y - c;\n        w[x][y] = dx * dx + dy * dy + 1;\n    }\n\n    vector<Point> initial(M);\n    for (int i = 0; i < M; i++) cin >> initial[i].x >> initial[i].y;\n\n    vector<Point> allPoints;\n    allPoints.reserve(N * N);\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) allPoints.push_back({x, y});\n    sort(allPoints.begin(), allPoints.end(), [&](const Point& a, const Point& b) {\n        int wa = w[a.x][a.y], wb = w[b.x][b.y];\n        if (wa != wb) return wa > wb;\n        if (a.x != b.x) return a.x < b.x;\n        return a.y < b.y;\n    });\n\n    auto start = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n    };\n\n    auto perimeterAxis = [&](int x1, int y1, int x2, int y2) -> int {\n        return 2 * (abs(x2 - x1) + abs(y2 - y1));\n    };\n    auto perimeterDiag = [&](const Point& p1, const Point& p2, const Point& p3) -> int {\n        int a = abs(p2.x - p1.x);\n        int b = abs(p3.x - p2.x);\n        return 2 * (a + b);\n    };\n\n    auto runOnce = [&](uint64_t seed, const Params& par) -> Result {\n        XorShift rng(seed);\n\n        State st(N);\n        st.shiftV = N - 1;\n        st.U = 2 * N - 1;\n        st.V = 2 * N - 1;\n        st.diagVdots.assign(st.V, Bits128{});\n        st.antiUdots.assign(st.U, Bits128{});\n        st.d1SegUsed.assign(st.V, 0ULL);\n        st.d2SegUsed.assign(st.U, 0ULL);\n        st.diagVCnt.assign(st.V, 0);\n        st.antiUCnt.assign(st.U, 0);\n\n        for (auto &x : st.dotRow) x = 0;\n        for (auto &x : st.dotCol) x = 0;\n        for (auto &x : st.hUsed) x = 0;\n        for (auto &x : st.vUsed) x = 0;\n        for (auto &x : st.rowCnt) x = 0;\n        for (auto &x : st.colCnt) x = 0;\n        st.dots = 0;\n        st.sumW = 0;\n\n        for (auto p : initial) {\n            st.addDot(p.x, p.y);\n            st.sumW += w[p.x][p.y];\n        }\n\n        vector<array<int, 8>> ops;\n        ops.reserve(N * N);\n\n        auto collectP1 = [&](int P) {\n            vector<Point> res;\n            res.reserve(P + par.randP);\n            for (const auto& p : allPoints) {\n                if ((int)res.size() >= P) break;\n                if (!st.hasDot(p.x, p.y)) res.push_back(p);\n            }\n            for (int i = 0; i < par.randP; i++) {\n                for (int t = 0; t < 40; t++) {\n                    int x = rng.nextInt(0, N - 1);\n                    int y = rng.nextInt(0, N - 1);\n                    if (!st.hasDot(x, y)) { res.push_back({x, y}); break; }\n                }\n            }\n            return res;\n        };\n\n        auto evalMove = [&](const Point& p1, int per, bool fillMode) -> double {\n            int x1 = p1.x, y1 = p1.y;\n            int u1 = x1 + y1;\n            int v1 = x1 - y1 + st.shiftV;\n            int conn = (int)st.rowCnt[y1] + (int)st.colCnt[x1] + (int)st.diagVCnt[v1] + (int)st.antiUCnt[u1];\n\n            double progress = (double)ops.size() / (double)max(1, (N * N - M));\n            progress = min(1.0, max(0.0, progress));\n\n            double alpha, beta, wcoef;\n            if (!fillMode) {\n                alpha = par.alphaStart * (1.0 - progress) + par.alphaEnd * progress;\n                beta  = par.betaStart  * (1.0 - progress) + par.betaEnd  * progress;\n                wcoef = 1.0;\n            } else {\n                alpha = par.fillAlpha;\n                beta  = par.fillBeta;\n                wcoef = par.fillWeightCoef;\n            }\n            return wcoef * (double)w[x1][y1] + beta * (double)conn - alpha * (double)per + par.noise * rng.nextDouble();\n        };\n\n        auto findBestMove = [&](Move& best, bool fillMode) -> bool {\n            best.val = -1e100;\n            bool found = false;\n\n            auto tryList = [&](int P) {\n                auto p1s = collectP1(P);\n                for (const auto& p1 : p1s) {\n                    int x1 = p1.x, y1 = p1.y;\n                    if (st.hasDot(x1, y1)) continue;\n\n                    // axis candidates\n                    uint64_t yMask = st.dotCol[x1];\n                    while (yMask) {\n                        int y2 = __builtin_ctzll(yMask);\n                        yMask &= yMask - 1;\n                        if (y2 == y1) continue;\n\n                        uint64_t inter = st.dotRow[y1] & st.dotRow[y2];\n                        inter &= ~(1ULL << x1);\n                        while (inter) {\n                            int x2 = __builtin_ctzll(inter);\n                            inter &= inter - 1;\n                            if (x2 == x1) continue;\n\n                            if (!st.canAxisRect(x1, y1, x2, y2)) continue;\n\n                            Move mv;\n                            mv.isAxis = true;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = {x2, y1};\n                            mv.p3 = {x2, y2};\n                            mv.p4 = {x1, y2};\n\n                            int per = perimeterAxis(x1, y1, x2, y2);\n                            double val = evalMove(p1, per, fillMode);\n                            if (val > best.val) { best = mv; best.val = val; found = true; }\n                        }\n                    }\n\n                    // diagonal candidates\n                    int u1 = x1 + y1;\n                    int v1Idx = x1 - y1 + st.shiftV;\n\n                    Bits128 vMask = st.antiUdots[u1];\n                    uint64_t vlo = vMask.lo, vhi = vMask.hi;\n\n                    auto handleV2 = [&](int v2Idx) {\n                        if (v2Idx == v1Idx) return;\n                        Bits128 interU = st.diagVdots[v1Idx] & st.diagVdots[v2Idx];\n                        if (u1 < 128) interU.reset(u1);\n                        if (!interU.any()) return;\n\n                        uint64_t ulo = interU.lo, uhi = interU.hi;\n                        auto handleU2 = [&](int u2) {\n                            if (u2 == u1) return;\n                            if (!st.canDiagRect(x1, y1, u2, v2Idx)) return;\n\n                            Point p2 = st.uvToXY(u2, v1Idx);\n                            Point p3 = st.uvToXY(u2, v2Idx);\n                            Point p4 = st.uvToXY(u1, v2Idx);\n\n                            Move mv;\n                            mv.isAxis = false;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = p2;\n                            mv.p3 = p3;\n                            mv.p4 = p4;\n\n                            int per = perimeterDiag(mv.p1, mv.p2, mv.p3);\n                            double val = evalMove(p1, per, fillMode);\n                            if (val > best.val) { best = mv; best.val = val; found = true; }\n                        };\n\n                        while (ulo) { int b = __builtin_ctzll(ulo); ulo &= ulo - 1; handleU2(b); }\n                        while (uhi) { int b = __builtin_ctzll(uhi); uhi &= uhi - 1; handleU2(64 + b); }\n                    };\n\n                    while (vlo) { int b = __builtin_ctzll(vlo); vlo &= vlo - 1; handleV2(b); }\n                    while (vhi) { int b = __builtin_ctzll(vhi); vhi &= vhi - 1; handleV2(64 + b); }\n                }\n            };\n\n            tryList(fillMode ? par.midP : par.topP);\n            if (found) return true;\n            tryList(fillMode ? (N * N) : par.midP);\n            return found;\n        };\n\n        while (elapsedSec() < 4.92) {\n            Move best;\n            if (!findBestMove(best, /*fillMode=*/false)) {\n                // fallback: favor short perimeter / connectivity to keep going\n                if (!findBestMove(best, /*fillMode=*/true)) break;\n            }\n\n            if (best.isAxis) st.applyAxisRect(best);\n            else st.applyDiagRect(best);\n\n            st.sumW += w[best.p1.x][best.p1.y];\n\n            ops.push_back({best.p1.x, best.p1.y,\n                           best.p2.x, best.p2.y,\n                           best.p3.x, best.p3.y,\n                           best.p4.x, best.p4.y});\n        }\n\n        Result res;\n        res.ops = std::move(ops);\n        res.sumW = st.sumW;\n        res.dots = st.dots;\n        return res;\n    };\n\n    // More restarts, pick best by sumW (true objective proxy)\n    vector<Params> plist;\n    {\n        Params p;\n        p.topP = 220; p.midP = 900; p.randP = 60;\n        p.alphaStart = 0.58; p.alphaEnd = 0.30;\n        p.betaStart = 2.2; p.betaEnd = 0.7;\n        p.fillAlpha = 0.90; p.fillBeta = 1.25; p.fillWeightCoef = 0.15;\n        p.noise = 0.02;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 300; p.midP = 1200; p.randP = 70;\n        p.alphaStart = 0.52; p.alphaEnd = 0.26;\n        p.betaStart = 1.8; p.betaEnd = 0.55;\n        p.fillAlpha = 0.85; p.fillBeta = 1.15; p.fillWeightCoef = 0.20;\n        p.noise = 0.025;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 180; p.midP = 800; p.randP = 50;\n        p.alphaStart = 0.62; p.alphaEnd = 0.32;\n        p.betaStart = 2.4; p.betaEnd = 0.80;\n        p.fillAlpha = 0.95; p.fillBeta = 1.30; p.fillWeightCoef = 0.10;\n        p.noise = 0.018;\n        plist.push_back(p);\n    }\n\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result bestRes;\n    bestRes.sumW = -1;\n\n    int trial = 0;\n    while (elapsedSec() < 4.93) {\n        const Params& par = plist[trial % (int)plist.size()];\n        uint64_t seed = baseSeed + 1000003ULL * (uint64_t)trial;\n        auto res = runOnce(seed, par);\n        if (res.sumW > bestRes.sumW || (res.sumW == bestRes.sumW && res.ops.size() > bestRes.ops.size())) {\n            bestRes = std::move(res);\n        }\n        trial++;\n    }\n\n    cout << bestRes.ops.size() << \"\\n\";\n    for (auto &a : bestRes.ops) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << a[i];\n        }\n        cout << \"\\n\";\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int M = 100;\n\n// ---------- RNG ----------\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n    inline double next_double01() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\n// ---------- Board ----------\nstruct Board {\n    array<uint8_t, M> a{}; // 0 empty, 1..3 flavors\n\n    inline uint8_t get(int r, int c) const { return a[r * N + c]; }\n    inline void set(int r, int c, uint8_t v) { a[r * N + c] = v; }\n\n    // dir: 0=F(up),1=B(down),2=L(left),3=R(right)\n    inline void tilt(int dir) {\n        if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                int base = r * N;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = (c < k ? tmp[c] : 0);\n            }\n        } else if (dir == 3) { // R\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                int base = r * N;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = 0;\n                for (int i = 0; i < k; i++) a[base + (N - 1 - i)] = tmp[i];\n            }\n        } else if (dir == 0) { // F (up)\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = (r < k ? tmp[r] : 0);\n            }\n        } else { // B (down)\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = 0;\n                for (int i = 0; i < k; i++) a[(N - 1 - i) * N + c] = tmp[i];\n            }\n        }\n    }\n\n    inline void place_by_p(int p, uint8_t flavor) {\n        // p is 1-indexed among empty cells in row-major order.\n        int cnt = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                if (++cnt == p) { a[i] = flavor; return; }\n            }\n        }\n    }\n\n    inline void place_random_empty(uint8_t flavor, XorShift64 &rng) {\n        int idxs[M];\n        int e = 0;\n        for (int i = 0; i < M; i++) if (a[i] == 0) idxs[e++] = i;\n        if (e == 0) return;\n        a[idxs[rng.next_int(e)]] = flavor;\n    }\n\n    inline int filled_count() const {\n        int f = 0;\n        for (int i = 0; i < M; i++) f += (a[i] != 0);\n        return f;\n    }\n};\n\n// ---------- Precomputed neighbors for BFS ----------\nstatic array<array<int, 4>, M> nbr{};\nstatic array<int, M> deg{};\n\nstatic inline void init_neighbors() {\n    for (int i = 0; i < M; i++) {\n        int r = i / N, c = i % N;\n        int d = 0;\n        auto add = [&](int nr, int nc) {\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return;\n            nbr[i][d++] = nr * N + nc;\n        };\n        add(r - 1, c);\n        add(r + 1, c);\n        add(r, c - 1);\n        add(r, c + 1);\n        deg[i] = d;\n    }\n}\n\n// ---------- Evaluation ----------\n// Soft targets (corners) to encourage macro separation.\nstatic constexpr int TR[4] = {0, 0, 0, 9};  // dummy at 0\nstatic constexpr int TC[4] = {0, 0, 9, 9};  // 1->(0,0), 2->(0,9), 3->(9,9)\n// Actually TR/TC above encode (r,c):\n// flavor 1: (0,0)\n// flavor 2: (0,9)\n// flavor 3: (9,9)\nstatic constexpr int RR[4] = {0, 0, 0, 9};\nstatic constexpr int CC[4] = {0, 0, 9, 9};\n\nstatic inline int dist_potential(const Board &b) {\n    // higher is better (closer to target)\n    int s = 0;\n    for (int i = 0; i < M; i++) {\n        uint8_t v = b.a[i];\n        if (!v) continue;\n        int r = i / N, c = i % N;\n        int dr = abs(r - RR[v]);\n        int dc = abs(c - CC[v]);\n        s -= (dr + dc);\n    }\n    return s;\n}\n\nstatic inline void adjacency_counts(const Board &b, int &same_adj, int &empty_adj) {\n    same_adj = 0;\n    empty_adj = 0;\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        uint8_t v = b.get(r, c);\n        if (c + 1 < N) {\n            uint8_t u = b.get(r, c + 1);\n            if (v && u && v == u) same_adj++;\n            if (!v && !u) empty_adj++;\n        }\n        if (r + 1 < N) {\n            uint8_t u = b.get(r + 1, c);\n            if (v && u && v == u) same_adj++;\n            if (!v && !u) empty_adj++;\n        }\n    }\n}\n\nstatic inline long long comp_sq_sum(const Board &b) {\n    bool vis[M];\n    memset(vis, 0, sizeof(vis));\n    int q[M];\n\n    long long sumsq = 0;\n    for (int i = 0; i < M; i++) {\n        if (b.a[i] == 0 || vis[i]) continue;\n        uint8_t col = b.a[i];\n        int head = 0, tail = 0;\n        vis[i] = true;\n        q[tail++] = i;\n        int cnt = 0;\n        while (head < tail) {\n            int v = q[head++];\n            cnt++;\n            for (int k = 0; k < deg[v]; k++) {\n                int to = nbr[v][k];\n                if (!vis[to] && b.a[to] == col) {\n                    vis[to] = true;\n                    q[tail++] = to;\n                }\n            }\n        }\n        sumsq += 1LL * cnt * cnt;\n    }\n    return sumsq;\n}\n\nstatic inline long long full_eval(const Board &b) {\n    // Stage-dependent weights: early emphasize shaping (distance), later emphasize connectivity.\n    int filled = b.filled_count();\n    long long cs = comp_sq_sum(b);\n    int same_adj, empty_adj;\n    adjacency_counts(b, same_adj, empty_adj);\n    int dp = dist_potential(b);\n\n    long long wComp = (filled < 25 ? 400 : (filled < 60 ? 1400 : 3200));\n    long long wAdj  = (filled < 25 ? 120 : (filled < 60 ? 80 : 60));\n    long long wDist = (filled < 25 ? 40 : (filled < 60 ? 18 : 10));\n    long long wEmp  = 4;\n\n    return cs * wComp + 1LL * same_adj * wAdj + 1LL * dp * wDist + 1LL * empty_adj * wEmp;\n}\n\nstatic inline int fast_eval(const Board &b) {\n    // Cheap proxy used only to choose actions inside rollouts.\n    int same_adj, empty_adj;\n    adjacency_counts(b, same_adj, empty_adj);\n    int dp = dist_potential(b);\n    return same_adj * 60 + dp * 15 + empty_adj * 2;\n}\n\nstatic inline char dir_char(int d) {\n    if (d == 0) return 'F';\n    if (d == 1) return 'B';\n    if (d == 2) return 'L';\n    return 'R';\n}\n\n// rollout policy: choose dir maximizing fast_eval after tilt (with slight randomness)\nstatic inline int rollout_policy(const Board &b, XorShift64 &rng) {\n    int best = INT_MIN;\n    int bestDirs[4];\n    int k = 0;\n\n    for (int d = 0; d < 4; d++) {\n        Board nb = b;\n        nb.tilt(d);\n        int v = fast_eval(nb);\n        if (v > best) {\n            best = v;\n            k = 0;\n            bestDirs[k++] = d;\n        } else if (v == best) {\n            bestDirs[k++] = d;\n        }\n    }\n\n    // epsilon randomization to reduce rollout determinism\n    if (rng.next_double01() < 0.08) return rng.next_int(4);\n    return bestDirs[rng.next_int(k)];\n}\n\nstatic inline long long simulate_rollout(Board b, int t_next, int depth,\n                                        const array<uint8_t, 100> &flv,\n                                        XorShift64 &rng) {\n    for (int step = 0; step < depth && t_next < 100; step++, t_next++) {\n        b.place_random_empty(flv[t_next], rng);\n        if (t_next == 99) break; // last candy: no tilt afterwards\n        int d = rollout_policy(b, rng);\n        b.tilt(d);\n    }\n    return full_eval(b);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_neighbors();\n\n    array<uint8_t, 100> flv{};\n    for (int i = 0; i < 100; i++) {\n        int x;\n        cin >> x;\n        flv[i] = (uint8_t)x;\n    }\n\n    // Deterministic seed from flavor sequence\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < 100; i++) seed = (seed ^ flv[i]) * 1099511628211ULL;\n    XorShift64 rng(seed);\n\n    Board cur;\n\n    auto t_start = chrono::steady_clock::now();\n    const double TL = 1.98; // aim below 2.0s\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        cin >> p;\n        cur.place_by_p(p, flv[t]);\n\n        if (t == 99) break; // no output needed\n\n        // Candidate boards after applying each possible tilt now\n        Board candB[4];\n        long long sum[4] = {};\n        int cnt[4] = {};\n\n        for (int d = 0; d < 4; d++) {\n            candB[d] = cur;\n            candB[d].tilt(d);\n            sum[d] = full_eval(candB[d]); // include 0-depth value\n            cnt[d] = 1;\n        }\n\n        int remainMoves = 99 - t; // number of outputs remaining including this one\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n        double left = TL - elapsed;\n        if (left < 0.0) left = 0.0;\n\n        // Per-move budget: proportional to remaining moves, with safety factor\n        double budget = (remainMoves > 0 ? left / remainMoves : 0.0);\n        budget *= 0.90;\n        budget = min(budget, 0.060);          // cap per move\n        budget = max(budget, 0.0015);         // minimum\n\n        int remain = 99 - t;\n        int depth = 3 + remain / 20;          // remain 99 -> 7, 40 -> 5, 15 -> 3\n        depth = min(depth, 9);\n        depth = min(depth, 100 - (t + 1));    // cannot exceed remaining candies\n\n        auto move_end = chrono::steady_clock::now() + chrono::duration<double>(budget);\n\n        // Rollouts round-robin among 4 candidates\n        int turn = 0;\n        while (chrono::steady_clock::now() < move_end) {\n            int d0 = turn & 3;\n            turn++;\n\n            // independent stream per candidate+turn\n            XorShift64 local_rng(rng.next_u64() ^ (uint64_t)(t * 911382323 + d0 * 972663749 + turn * 19260817));\n\n            long long v = simulate_rollout(candB[d0], t + 1, depth, flv, local_rng);\n            sum[d0] += v;\n            cnt[d0] += 1;\n        }\n\n        // choose best average\n        int bestDir = 0;\n        long double bestScore = -1e100L;\n        for (int d = 0; d < 4; d++) {\n            long double avg = (long double)sum[d] / (long double)cnt[d];\n            if (avg > bestScore) {\n                bestScore = avg;\n                bestDir = d;\n            }\n        }\n\n        cout << dir_char(bestDir) << '\\n' << flush;\n        cur.tilt(bestDir);\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u64() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstatic vector<double> binom_pmf(int n, double p) {\n    vector<double> pmf(n+1, 0.0);\n    if (n == 0) { pmf[0] = 1.0; return pmf; }\n    if (p <= 0.0) { pmf[0] = 1.0; return pmf; }\n    if (p >= 1.0) { pmf[n] = 1.0; return pmf; }\n    double q = 1.0 - p;\n    pmf[0] = pow(q, n);\n    double ratio = p / q;\n    for (int k = 1; k <= n; k++) {\n        pmf[k] = pmf[k-1] * (double)(n - k + 1) / (double)k * ratio;\n    }\n    return pmf;\n}\n\nstatic int chooseN(int M, double eps) {\n    // Conservative mapping; bigger eps => bigger N\n    if (eps <= 0.05) return 25;\n    if (eps <= 0.10) return 35;\n    if (eps <= 0.20) return 50;\n    if (eps <= 0.30) return 75;\n    if (eps <= 0.35) return 90;\n    return 100;\n}\n\nstatic int ceil_log2_int(int x) {\n    int r = 0;\n    int v = 1;\n    while (v < x) { v <<= 1; r++; }\n    return r;\n}\n\nstatic string key_of(const vector<int>& v) {\n    string s;\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (i) s.push_back('-');\n        s += to_string(v[i]);\n    }\n    return s;\n}\n\nstatic double dist_L1(const vector<int>& a, const vector<int>& b) {\n    double d = 0;\n    for (int i = 0; i < (int)a.size(); i++) d += abs(a[i] - b[i]);\n    return d;\n}\n\n// Generate a random partition of N into B parts, each >= ms.\n// Optionally enforce strictly decreasing sizes (after sorting desc) if feasible.\nstatic bool gen_partition(int N, int B, int ms, bool enforce_unique_desc,\n                          SplitMix64& rng, vector<int>& out) {\n    int base = ms * B;\n    if (base > N) return false;\n    int rem = N - base;\n\n    vector<double> w(B);\n    double sumw = 0.0;\n    for (int i = 0; i < B; i++) {\n        w[i] = rng.next_double() + 1e-12;\n        sumw += w[i];\n    }\n\n    vector<int> add(B, 0);\n    vector<pair<double,int>> frac;\n    frac.reserve(B);\n    int sumAdd = 0;\n    for (int i = 0; i < B; i++) {\n        double x = rem * (w[i] / sumw);\n        int a = (int)floor(x);\n        add[i] = a;\n        sumAdd += a;\n        frac.push_back({x - a, i});\n    }\n    int left = rem - sumAdd;\n    sort(frac.begin(), frac.end(), [&](auto& p1, auto& p2){ return p1.first > p2.first; });\n    for (int t = 0; t < left; t++) add[frac[t].second]++;\n\n    out.assign(B, ms);\n    for (int i = 0; i < B; i++) out[i] += add[i];\n\n    sort(out.begin(), out.end(), greater<int>());\n\n    if (enforce_unique_desc) {\n        for (int i = 0; i+1 < B; i++) if (out[i] <= out[i+1]) return false;\n    }\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    int N = chooseN(M, eps);\n    int L = N * (N - 1) / 2;\n\n    // Decide minimum clique size (avoid too tiny blocks at high eps)\n    int ms;\n    if (eps <= 0.10) ms = 1;\n    else if (eps <= 0.20) ms = 2;\n    else if (eps <= 0.30) ms = 3;\n    else ms = 4;\n\n    // Decide number of blocks B\n    int targetSize;\n    if (eps <= 0.10) targetSize = 5;\n    else if (eps <= 0.20) targetSize = 7;\n    else if (eps <= 0.30) targetSize = 9;\n    else targetSize = 11;\n\n    int B0 = max(3, min(12, N / targetSize));\n    int B = max(B0, ceil_log2_int(M) + 1);\n    B = min(B, 12);\n    while (B >= 3 && B * ms > N) B--;\n    if (B < 3) B = 3;\n\n    // Can we enforce unique descending sizes?\n    // Need N >= B*ms + (B-1 + ... + 0) = B*ms + B*(B-1)/2\n    bool enforce_unique_desc = (N >= B * ms + B * (B - 1) / 2);\n\n    // Deterministic RNG seed from (M, eps)\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)M * 1000003ULL;\n    seed ^= (uint64_t)llround(eps * 1000.0) * 10007ULL;\n    SplitMix64 rng(seed);\n\n    // Precompute logP[s][d] for degree distribution given clique size s\n    vector<vector<double>> logP(N+1, vector<double>(N, -1e100));\n    for (int s = 1; s <= N; s++) {\n        int n1 = s - 1;\n        int n2 = N - s;\n        double p1 = 1.0 - eps;\n        double p2 = eps;\n        auto pmf1 = binom_pmf(n1, p1);\n        auto pmf2 = binom_pmf(n2, p2);\n        vector<double> conv(N, 0.0);\n        for (int a = 0; a <= n1; a++) {\n            double pa = pmf1[a];\n            if (pa == 0.0) continue;\n            for (int b = 0; b <= n2; b++) {\n                double pb = pmf2[b];\n                if (pb == 0.0) continue;\n                conv[a + b] += pa * pb;\n            }\n        }\n        for (int d = 0; d <= N-1; d++) {\n            double v = max(conv[d], 1e-300);\n            logP[s][d] = log(v);\n        }\n    }\n\n    // Build pool of candidate partitions\n    int poolTarget = 20000;\n    vector<vector<int>> pool;\n    pool.reserve(poolTarget);\n    unordered_set<string> seen;\n    seen.reserve(poolTarget * 2);\n\n    auto build_pool = [&](bool uniq) {\n        pool.clear();\n        seen.clear();\n        int tries = 0;\n        int maxTries = poolTarget * 20;\n        while ((int)pool.size() < poolTarget && tries < maxTries) {\n            tries++;\n            vector<int> part;\n            if (!gen_partition(N, B, ms, uniq, rng, part)) continue;\n            string k = key_of(part);\n            if (seen.insert(k).second) pool.push_back(std::move(part));\n        }\n    };\n\n    build_pool(enforce_unique_desc);\n    if ((int)pool.size() < max(M, 200)) {\n        // Relax uniqueness if too few\n        enforce_unique_desc = false;\n        build_pool(false);\n    }\n\n    // Farthest-point sampling to select M well-separated partitions\n    int P = (int)pool.size();\n    vector<int> chosenIdx;\n    chosenIdx.reserve(M);\n\n    // choose first: maximize spread (max-min)\n    int first = 0;\n    double bestSpread = -1;\n    for (int i = 0; i < P; i++) {\n        double spread = pool[i].front() - pool[i].back();\n        if (spread > bestSpread) { bestSpread = spread; first = i; }\n    }\n    chosenIdx.push_back(first);\n\n    vector<double> mind(P, 1e100);\n    vector<char> used(P, 0);\n    used[first] = 1;\n    for (int i = 0; i < P; i++) mind[i] = dist_L1(pool[i], pool[first]);\n\n    while ((int)chosenIdx.size() < M) {\n        int best = -1;\n        double bestVal = -1;\n        for (int i = 0; i < P; i++) {\n            if (used[i]) continue;\n            if (mind[i] > bestVal) { bestVal = mind[i]; best = i; }\n        }\n        if (best < 0) break;\n        used[best] = 1;\n        chosenIdx.push_back(best);\n        for (int i = 0; i < P; i++) {\n            if (used[i]) continue;\n            double d = dist_L1(pool[i], pool[best]);\n            if (d < mind[i]) mind[i] = d;\n        }\n    }\n\n    // If still short (unlikely), fill by random distinct from pool\n    for (int i = 0; (int)chosenIdx.size() < M && i < P; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            chosenIdx.push_back(i);\n        }\n    }\n\n    // Final codebook: clique size vectors\n    vector<vector<int>> codes(M);\n    for (int k = 0; k < M; k++) codes[k] = pool[chosenIdx[k]];\n\n    // Precompute original edge counts E_k\n    vector<int> Eorig(M, 0);\n    for (int k = 0; k < M; k++) {\n        long long E = 0;\n        for (int s : codes[k]) E += 1LL * s * (s - 1) / 2;\n        Eorig[k] = (int)E;\n    }\n\n    // Output graphs\n    cout << N << '\\n';\n    for (int k = 0; k < M; k++) {\n        const auto& part = codes[k];\n        vector<int> blk(N, -1);\n        int cur = 0;\n        for (int b = 0; b < (int)part.size(); b++) {\n            for (int t = 0; t < part[b]; t++) blk[cur++] = b;\n        }\n        string g;\n        g.reserve(L);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                g.push_back(blk[i] == blk[j] ? '1' : '0');\n            }\n        }\n        cout << g << '\\n';\n    }\n    cout.flush();\n\n    // Decode 100 queries\n    const double var_edges = (eps > 0.0 && eps < 1.0) ? (double)L * eps * (1.0 - eps) : 1.0;\n    const double wEdge = 0.10; // small auxiliary weight\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) break;\n\n        vector<int> deg(N, 0);\n        int m = 0;\n        int idx = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                char c = H[idx++];\n                if (c == '1') {\n                    deg[i]++; deg[j]++;\n                    m++;\n                }\n            }\n        }\n        sort(deg.begin(), deg.end(), greater<int>());\n\n        int bestK = 0;\n        double bestScore = -1e300;\n\n        for (int k = 0; k < M; k++) {\n            const auto& part = codes[k];\n            double sc = 0.0;\n            int pos = 0;\n            for (int s : part) {\n                for (int t = 0; t < s; t++) {\n                    int d = deg[pos++];\n                    sc += logP[s][d];\n                }\n            }\n\n            if (eps > 0.0 && eps < 1.0) {\n                double mu = eps * (double)L + (1.0 - 2.0 * eps) * (double)Eorig[k];\n                double z = (m - mu);\n                sc += wEdge * (-0.5 * (z * z) / var_edges);\n            }\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestK = k;\n            }\n        }\n\n        cout << bestK << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline long long comb2(long long c) { return c * (c - 1) / 2; }\n\n// Morton key for 0..2047 (11 bits)\nstatic inline uint64_t morton11(uint32_t x, uint32_t y) {\n    uint64_t key = 0;\n    for (int b = 0; b < 11; b++) {\n        key |= (uint64_t)((x >> b) & 1u) << (2 * b);\n        key |= (uint64_t)((y >> b) & 1u) << (2 * b + 1);\n    }\n    return key;\n}\n\nstruct Edge {\n    int u, v;\n    long long w;\n    uint64_t key;\n    int prefDay;\n    long double imp; // scaled to [0,1]\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, D, K;\n    cin >> N >> M >> D >> K;\n\n    vector<Edge> edges(M);\n    vector<long long> W(M);\n    vector<vector<pair<int,int>>> g(N); // (to, edgeId)\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i].u = u;\n        edges[i].v = v;\n        edges[i].w = w;\n        W[i] = w;\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    vector<int> X(N), Y(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n    // ---- Build a DFS spanning tree for LCA and 2-edge-cut detection ----\n    vector<int> parent(N, -1), parentEdge(N, -1), depth(N, 0);\n    vector<int> tin(N, -1), tout(N, -1), order;\n    vector<char> vis(N, 0), isTreeEdge(M, 0);\n    int timer = 0;\n\n    function<void(int)> dfs = [&](int v) {\n        vis[v] = 1;\n        tin[v] = timer++;\n        order.push_back(v);\n        for (auto [to, eid] : g[v]) {\n            if (to == parent[v]) continue;\n            if (!vis[to]) {\n                parent[to] = v;\n                parentEdge[to] = eid;\n                depth[to] = depth[v] + 1;\n                isTreeEdge[eid] = 1;\n                dfs(to);\n            }\n        }\n        tout[v] = timer++;\n    };\n\n    int root = 0;\n    dfs(root);\n\n    // Binary lifting for LCA\n    int LOG = 1;\n    while ((1 << LOG) <= N) LOG++;\n    vector<vector<int>> up(LOG, vector<int>(N, -1));\n    for (int i = 0; i < N; i++) up[0][i] = parent[i];\n    for (int k = 1; k < LOG; k++) {\n        for (int i = 0; i < N; i++) {\n            int p = up[k-1][i];\n            up[k][i] = (p == -1 ? -1 : up[k-1][p]);\n        }\n    }\n\n    auto is_ancestor = [&](int a, int b) -> bool {\n        return tin[a] <= tin[b] && tout[b] <= tout[a];\n    };\n\n    auto lca = [&](int a, int b) -> int {\n        if (a == -1 || b == -1) return -1;\n        if (is_ancestor(a, b)) return a;\n        if (is_ancestor(b, a)) return b;\n        int v = a;\n        for (int k = LOG - 1; k >= 0; k--) {\n            int p = up[k][v];\n            if (p != -1 && !is_ancestor(p, b)) v = p;\n        }\n        return parent[v];\n    };\n\n    // ---- Detect many 2-edge-cuts of size 2: (tree edge, unique crossing non-tree edge) ----\n    vector<long long> cntDelta(N, 0), cntSub(N, 0);\n    vector<int> xorDelta(N, 0), xorSub(N, 0);\n\n    for (int eid = 0; eid < M; eid++) {\n        if (isTreeEdge[eid]) continue;\n        int u = edges[eid].u;\n        int v = edges[eid].v;\n        int L = lca(u, v);\n\n        // count crossing edges using standard -2 at L\n        cntDelta[u] += 1;\n        cntDelta[v] += 1;\n        cntDelta[L] -= 2;\n\n        // xor of crossing edges for each subtree cut: just toggle endpoints\n        xorDelta[u] ^= eid;\n        xorDelta[v] ^= eid;\n    }\n\n    for (int i = 0; i < N; i++) {\n        cntSub[i] = cntDelta[i];\n        xorSub[i] = xorDelta[i];\n    }\n\n    // postorder accumulation using reverse of DFS order (works since parent discovered before children)\n    for (int idx = (int)order.size() - 1; idx >= 1; idx--) {\n        int v = order[idx];\n        int p = parent[v];\n        cntSub[p] += cntSub[v];\n        xorSub[p] ^= xorSub[v];\n    }\n\n    vector<vector<int>> conflict(M);\n    vector<pair<int,int>> conflictPairs;\n    for (int v = 1; v < N; v++) {\n        long long cover = cntSub[v];\n        if (cover == 1) {\n            int eTree = parentEdge[v];\n            int eNonTree = xorSub[v];\n            if (eTree >= 0 && eNonTree >= 0 && eTree != eNonTree) {\n                conflict[eTree].push_back(eNonTree);\n                conflict[eNonTree].push_back(eTree);\n                if (eTree < eNonTree) conflictPairs.push_back({eTree, eNonTree});\n                else conflictPairs.push_back({eNonTree, eTree});\n            }\n        }\n    }\n    for (int i = 0; i < M; i++) {\n        auto &c = conflict[i];\n        sort(c.begin(), c.end());\n        c.erase(unique(c.begin(), c.end()), c.end());\n    }\n    sort(conflictPairs.begin(), conflictPairs.end());\n    conflictPairs.erase(unique(conflictPairs.begin(), conflictPairs.end()), conflictPairs.end());\n\n    // ---- Edge importance estimation via sampled shortest path trees ----\n    long double meanW = 0;\n    for (auto &e : edges) meanW += (long double)e.w;\n    meanW /= max(1, M);\n\n    // select sources by farthest point sampling in coordinate space\n    int S = min(60, N);\n    vector<int> sources;\n    sources.reserve(S);\n    vector<long long> bestDist2(N, (1LL<<62));\n    int first = 0;\n    sources.push_back(first);\n    bestDist2[first] = 0;\n\n    for (int it = 1; it < S; it++) {\n        int last = sources.back();\n        for (int v = 0; v < N; v++) {\n            long long dx = X[v] - X[last];\n            long long dy = Y[v] - Y[last];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 < bestDist2[v]) bestDist2[v] = d2;\n        }\n        int farV = 0;\n        for (int v = 1; v < N; v++) if (bestDist2[v] > bestDist2[farV]) farV = v;\n        sources.push_back(farV);\n    }\n\n    vector<long double> rawImp(M, 0.0L);\n    const long long INF = (1LL<<62);\n\n    vector<long long> dist(N);\n    vector<int> parV(N), parE(N);\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int s : sources) {\n        // Dijkstra\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dist[s] = 0;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dist[v]) continue;\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parV[to] = v;\n                    parE[to] = eid;\n                    pq.push({nd, to});\n                } else if (nd == dist[to]) {\n                    // tie-breaker to stabilize: smaller edge id\n                    if (parE[to] == -1 || eid < parE[to]) {\n                        parV[to] = v;\n                        parE[to] = eid;\n                    }\n                }\n            }\n        }\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n\n        vector<int> sub(N, 1);\n        for (int v : ord) {\n            int p = parV[v];\n            if (p != -1) sub[p] += sub[v];\n        }\n\n        for (int v = 0; v < N; v++) {\n            int eid = parE[v];\n            if (eid == -1) continue;\n            long double factor = 1.0L + (long double)W[eid] / meanW;\n            rawImp[eid] += (long double)sub[v] * factor;\n        }\n    }\n\n    long double maxRaw = 1e-18L;\n    for (int i = 0; i < M; i++) maxRaw = max(maxRaw, rawImp[i]);\n    for (int i = 0; i < M; i++) edges[i].imp = rawImp[i] / maxRaw;\n\n    // ---- Initial spatial partition by Morton order of edge midpoint ----\n    vector<int> idx(M);\n    iota(idx.begin(), idx.end(), 0);\n    for (int i = 0; i < M; i++) {\n        // midpoint sums: 0..2000 => fit in 11 bits\n        uint32_t mx = (uint32_t)(X[edges[i].u] + X[edges[i].v]);\n        uint32_t my = (uint32_t)(Y[edges[i].u] + Y[edges[i].v]);\n        edges[i].key = morton11(mx, my);\n    }\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        return edges[a].key < edges[b].key;\n    });\n\n    vector<int> dayOfEdge(M, 0);\n    int base = M / D, rem = M % D;\n    vector<int> target(D, base);\n    for (int d = 0; d < rem; d++) target[d]++;\n\n    int cur = 0;\n    for (int d = 0; d < D; d++) {\n        for (int t = 0; t < target[d]; t++) {\n            int eid = idx[cur++];\n            dayOfEdge[eid] = d;\n        }\n    }\n    // preference = initial day\n    for (int i = 0; i < M; i++) edges[i].prefDay = dayOfEdge[i];\n\n    // Build day lists + positions for fast move\n    vector<vector<int>> inDay(D);\n    vector<int> posInDay(M, -1);\n    auto rebuildDayLists = [&]() {\n        for (int d = 0; d < D; d++) inDay[d].clear();\n        for (int e = 0; e < M; e++) {\n            int d = dayOfEdge[e];\n            posInDay[e] = (int)inDay[d].size();\n            inDay[d].push_back(e);\n        }\n    };\n    rebuildDayLists();\n\n    auto applyMoveOnlyLists = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        // remove from old\n        int p = posInDay[e];\n        int last = inDay[od].back();\n        inDay[od][p] = last;\n        posInDay[last] = p;\n        inDay[od].pop_back();\n        // add to new\n        posInDay[e] = (int)inDay[nd].size();\n        inDay[nd].push_back(e);\n        dayOfEdge[e] = nd;\n    };\n\n    auto canPlaceEdgeInDay = [&](int e, int d) -> bool {\n        for (int p : conflict[e]) {\n            if (dayOfEdge[p] == d) return false;\n        }\n        return true;\n    };\n\n    // ---- Fix conflicts greedily using slack in K ----\n    for (auto [a, b] : conflictPairs) {\n        if (dayOfEdge[a] != dayOfEdge[b]) continue;\n        int badDay = dayOfEdge[a];\n\n        bool fixed = false;\n        // try moving b first\n        for (int nd = 0; nd < D; nd++) {\n            if (nd == badDay) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceEdgeInDay(b, nd)) continue;\n            applyMoveOnlyLists(b, nd);\n            fixed = true;\n            break;\n        }\n        if (!fixed) {\n            // try moving a\n            for (int nd = 0; nd < D; nd++) {\n                if (nd == badDay) continue;\n                if ((int)inDay[nd].size() >= K) continue;\n                if (!canPlaceEdgeInDay(a, nd)) continue;\n                applyMoveOnlyLists(a, nd);\n                fixed = true;\n                break;\n            }\n        }\n        // if still not fixed, leave it; SA will likely resolve later (rare).\n    }\n\n    // ---- Rebuild day lists to be safe ----\n    rebuildDayLists();\n\n    // ---- Stats for SA cost ----\n    // Cost = A*sum_d(sumImp[d]^2) + PV*sum_{d,v} C(cnt[d][v],2) + B*misCount\n    const long double A = 1.0L;\n    const long double PV = 5.0L;\n    const long double B = 0.02L;\n\n    vector<long double> sumImp(D, 0.0L);\n    vector<vector<int>> inc(D, vector<int>(N, 0));\n    vector<long long> dayPairs(D, 0);\n    long long misCount = 0;\n\n    auto rebuildStats = [&]() {\n        fill(sumImp.begin(), sumImp.end(), 0.0L);\n        for (int d = 0; d < D; d++) fill(inc[d].begin(), inc[d].end(), 0);\n        fill(dayPairs.begin(), dayPairs.end(), 0LL);\n        misCount = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = dayOfEdge[e];\n            sumImp[d] += edges[e].imp;\n            if (dayOfEdge[e] != edges[e].prefDay) misCount++;\n            int u = edges[e].u, v = edges[e].v;\n            inc[d][u]++; inc[d][v]++;\n        }\n        for (int d = 0; d < D; d++) {\n            long long pairs = 0;\n            for (int v = 0; v < N; v++) pairs += comb2(inc[d][v]);\n            dayPairs[d] = pairs;\n        }\n    };\n    rebuildStats();\n\n    auto computeCost = [&]() -> long double {\n        long double s = 0;\n        for (int d = 0; d < D; d++) s += sumImp[d] * sumImp[d];\n        long double p = 0;\n        for (int d = 0; d < D; d++) p += (long double)dayPairs[d];\n        return A * s + PV * p + B * (long double)misCount;\n    };\n\n    long double curCost = computeCost();\n\n    auto hardCheckSwap = [&](int e1, int e2, int d1, int d2) -> bool {\n        // after swap: e1->d2, e2->d1\n        auto newDay = [&](int e)->int {\n            if (e == e1) return d2;\n            if (e == e2) return d1;\n            return dayOfEdge[e];\n        };\n        for (int p : conflict[e1]) if (newDay(p) == d2) return false;\n        for (int p : conflict[e2]) if (newDay(p) == d1) return false;\n        return true;\n    };\n\n    auto hardCheckMove = [&](int e, int nd) -> bool {\n        if ((int)inDay[nd].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == nd) return false;\n        return true;\n    };\n\n    auto applyMoveWithStats = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n\n        // update cost parts: sumImp^2\n        long double sa = sumImp[od], sb = sumImp[nd];\n        long double imp = edges[e].imp;\n        long double deltaImpSq = (sa - imp) * (sa - imp) + (sb + imp) * (sb + imp) - sa * sa - sb * sb;\n\n        // mis\n        long long oldMis = (od != edges[e].prefDay);\n        long long newMis = (nd != edges[e].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // vertex pairs delta (two vertices, two days)\n        int u = edges[e].u, v = edges[e].v;\n        long long deltaPairs = 0;\n\n        auto updOne = [&](int day, int vert, int dc) {\n            int oldc = inc[day][vert];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        };\n        updOne(od, u, -1); updOne(od, v, -1);\n        updOne(nd, u, +1); updOne(nd, v, +1);\n\n        // apply to stats\n        curCost += A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp[od] -= imp;\n        sumImp[nd] += imp;\n        misCount += deltaMis;\n\n        // apply incidence and dayPairs\n        auto applyInc = [&](int day, int vert, int dc) {\n            dayPairs[day] -= comb2(inc[day][vert]);\n            inc[day][vert] += dc;\n            dayPairs[day] += comb2(inc[day][vert]);\n        };\n        applyInc(od, u, -1); applyInc(od, v, -1);\n        applyInc(nd, u, +1); applyInc(nd, v, +1);\n\n        // apply to day lists\n        applyMoveOnlyLists(e, nd);\n    };\n\n    auto applySwapWithStats = [&](int e1, int e2) {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        if (d1 == d2) return;\n\n        // sumImp^2 delta\n        long double s1 = sumImp[d1], s2 = sumImp[d2];\n        long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n        long double ns1 = s1 - i1 + i2;\n        long double ns2 = s2 - i2 + i1;\n        long double deltaImpSq = ns1*ns1 + ns2*ns2 - s1*s1 - s2*s2;\n\n        // mis delta\n        long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n        long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // vertex pair delta: handle up to 8 (day,vertex) updates, merge by brute force\n        struct Mod { int day, v, dc; };\n        vector<Mod> mods;\n        mods.reserve(8);\n        auto addMod = [&](int day, int v, int dc){ mods.push_back({day, v, dc}); };\n        addMod(d1, edges[e1].u, -1); addMod(d1, edges[e1].v, -1);\n        addMod(d2, edges[e1].u, +1); addMod(d2, edges[e1].v, +1);\n        addMod(d2, edges[e2].u, -1); addMod(d2, edges[e2].v, -1);\n        addMod(d1, edges[e2].u, +1); addMod(d1, edges[e2].v, +1);\n\n        // merge duplicates\n        long long deltaPairs = 0;\n        for (int i = 0; i < (int)mods.size(); i++) {\n            int day = mods[i].day, v = mods[i].v;\n            int dc = mods[i].dc;\n            for (int j = i+1; j < (int)mods.size(); j++) {\n                if (mods[j].day == day && mods[j].v == v) {\n                    dc += mods[j].dc;\n                    mods[j].dc = 0;\n                }\n            }\n            if (dc == 0) continue;\n            int oldc = inc[day][v];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        }\n\n        // apply\n        curCost += A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp[d1] = ns1;\n        sumImp[d2] = ns2;\n        misCount += deltaMis;\n\n        auto applyInc = [&](int day, int v, int dc) {\n            dayPairs[day] -= comb2(inc[day][v]);\n            inc[day][v] += dc;\n            dayPairs[day] += comb2(inc[day][v]);\n        };\n\n        // apply all mods again (without merge) because applyInc already handles incremental correctly\n        applyInc(d1, edges[e1].u, -1); applyInc(d1, edges[e1].v, -1);\n        applyInc(d2, edges[e1].u, +1); applyInc(d2, edges[e1].v, +1);\n        applyInc(d2, edges[e2].u, -1); applyInc(d2, edges[e2].v, -1);\n        applyInc(d1, edges[e2].u, +1); applyInc(d1, edges[e2].v, +1);\n\n        // swap in lists\n        applyMoveOnlyLists(e1, d2);\n        applyMoveOnlyLists(e2, d1);\n    };\n\n    // ---- Simulated annealing ----\n    XorShift64 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 5.8;\n\n    int iters = 0;\n    while (true) {\n        iters++;\n        if ((iters & 2047) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed > TIME_LIMIT) break;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = elapsed / TIME_LIMIT;\n        double T = 5.0 * (1.0 - t) + 0.05 * t; // cooling\n\n        int op = rng.nextInt(100);\n        if (op < 75) {\n            // swap\n            int e1 = rng.nextInt(M);\n            int e2 = rng.nextInt(M);\n            if (e1 == e2) continue;\n            int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n            if (d1 == d2) continue;\n            if (!hardCheckSwap(e1, e2, d1, d2)) continue;\n\n            // compute delta by simulating cost difference (cheaply) using current stats\n            long double oldC = curCost;\n\n            // compute prospective delta (repeat same calculations as applySwapWithStats, but without applying)\n            long double s1 = sumImp[d1], s2 = sumImp[d2];\n            long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n            long double ns1 = s1 - i1 + i2;\n            long double ns2 = s2 - i2 + i1;\n            long double deltaImpSq = ns1*ns1 + ns2*ns2 - s1*s1 - s2*s2;\n\n            long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n            long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            // vertex pair delta (same mod merge trick)\n            struct Mod { int day, v, dc; };\n            array<Mod,8> mods = {{\n                {d1, edges[e1].u, -1}, {d1, edges[e1].v, -1},\n                {d2, edges[e1].u, +1}, {d2, edges[e1].v, +1},\n                {d2, edges[e2].u, -1}, {d2, edges[e2].v, -1},\n                {d1, edges[e2].u, +1}, {d1, edges[e2].v, +1},\n            }};\n            long long deltaPairs = 0;\n            for (int i = 0; i < 8; i++) {\n                int day = mods[i].day, v = mods[i].v;\n                int dc = mods[i].dc;\n                if (dc == 0) continue;\n                for (int j = i+1; j < 8; j++) {\n                    if (mods[j].day == day && mods[j].v == v) {\n                        dc += mods[j].dc;\n                        mods[j].dc = 0;\n                    }\n                }\n                int oldc = inc[day][v];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            }\n\n            long double delta = A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(-(double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) {\n                applySwapWithStats(e1, e2);\n            } else {\n                curCost = oldC;\n            }\n        } else {\n            // move\n            int e = rng.nextInt(M);\n            int od = dayOfEdge[e];\n            int nd = rng.nextInt(D);\n            if (nd == od) continue;\n            if (!hardCheckMove(e, nd)) continue;\n\n            // prospective delta\n            long double sa = sumImp[od], sb = sumImp[nd];\n            long double imp = edges[e].imp;\n            long double deltaImpSq = (sa - imp) * (sa - imp) + (sb + imp) * (sb + imp) - sa * sa - sb * sb;\n\n            long long oldMis = (od != edges[e].prefDay);\n            long long newMis = (nd != edges[e].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            int u = edges[e].u, v = edges[e].v;\n            long long deltaPairs = 0;\n            auto updOne = [&](int day, int vert, int dc) {\n                int oldc = inc[day][vert];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            };\n            updOne(od, u, -1); updOne(od, v, -1);\n            updOne(nd, u, +1); updOne(nd, v, +1);\n\n            long double delta = A * deltaImpSq + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(-(double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) applyMoveWithStats(e, nd);\n        }\n    }\n\n    // Final safety: ensure capacity <= K (should already hold)\n    // If any day exceeds K, move random edges out.\n    for (int d = 0; d < D; d++) {\n        while ((int)inDay[d].size() > K) {\n            int e = inDay[d].back();\n            bool moved = false;\n            for (int nd = 0; nd < D; nd++) {\n                if (nd == d) continue;\n                if ((int)inDay[nd].size() >= K) continue;\n                if (!canPlaceEdgeInDay(e, nd)) continue;\n                applyMoveOnlyLists(e, nd);\n                moved = true;\n                break;\n            }\n            if (!moved) break; // extremely unlikely\n        }\n    }\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (dayOfEdge[i] + 1);\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Segment {\n    int x, y, z;   // start coordinate\n    int axis;      // 0:x, 1:y, 2:z\n    int len;\n};\n\nstruct Piece {\n    int segId;\n    int off;\n    int len;\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstatic long long volume_of(const vector<uint8_t>& occ) {\n    long long v = 0;\n    for (auto c : occ) v += (c != 0);\n    return v;\n}\n\n// Extract maximal consecutive occupied segments along an axis.\nstatic vector<Segment> extract_segments(int D, const vector<uint8_t>& occ, int axis) {\n    vector<Segment> segs;\n    if (axis == 0) { // along x, fixed (y,z)\n        for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int x = 0;\n            while (x < D) {\n                if (!occ[idx3(D, x, y, z)]) { x++; continue; }\n                int xs = x;\n                while (x < D && occ[idx3(D, x, y, z)]) x++;\n                segs.push_back(Segment{xs, y, z, axis, x - xs});\n            }\n        }\n    } else if (axis == 1) { // along y, fixed (x,z)\n        for (int x = 0; x < D; x++) for (int z = 0; z < D; z++) {\n            int y = 0;\n            while (y < D) {\n                if (!occ[idx3(D, x, y, z)]) { y++; continue; }\n                int ys = y;\n                while (y < D && occ[idx3(D, x, y, z)]) y++;\n                segs.push_back(Segment{x, ys, z, axis, y - ys});\n            }\n        }\n    } else { // axis==2 along z, fixed (x,y)\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                if (!occ[idx3(D, x, y, z)]) { z++; continue; }\n                int zs = z;\n                while (z < D && occ[idx3(D, x, y, z)]) z++;\n                segs.push_back(Segment{x, y, zs, axis, z - zs});\n            }\n        }\n    }\n    return segs;\n}\n\n// DP to choose stable representative per z (maximize staying same between adjacent z).\nstatic vector<int> choose_stable_sequence(const vector<vector<int>>& opts) {\n    int D = (int)opts.size();\n    vector<vector<int>> par(D);\n    vector<long long> dp_prev, dp_cur;\n\n    dp_prev.assign(opts[0].size(), 0);\n    par[0].assign(opts[0].size(), -1);\n\n    for (int z = 1; z < D; z++) {\n        dp_cur.assign(opts[z].size(), LLONG_MIN / 4);\n        par[z].assign(opts[z].size(), -1);\n        for (int j = 0; j < (int)opts[z].size(); j++) {\n            for (int p = 0; p < (int)opts[z - 1].size(); p++) {\n                long long cand = dp_prev[p] + (opts[z][j] == opts[z - 1][p] ? 1 : 0);\n                if (cand > dp_cur[j]) {\n                    dp_cur[j] = cand;\n                    par[z][j] = p;\n                }\n            }\n        }\n        dp_prev.swap(dp_cur);\n    }\n\n    int bestj = 0;\n    for (int j = 1; j < (int)dp_prev.size(); j++) if (dp_prev[j] > dp_prev[bestj]) bestj = j;\n\n    vector<int> seq(D);\n    int cur = bestj;\n    for (int z = D - 1; z >= 0; z--) {\n        seq[z] = opts[z][cur];\n        cur = par[z][cur];\n        if (z == 0) break;\n    }\n    return seq;\n}\n\nstatic int choose_global_hub(const vector<vector<int>>& opts, int D) {\n    vector<int> freq(D, 0);\n    for (int z = 0; z < (int)opts.size(); z++) for (int v : opts[z]) freq[v]++;\n    int best = 0;\n    for (int i = 1; i < D; i++) {\n        if (freq[i] > freq[best]) best = i;\n    }\n    return best;\n}\n\n// Construction types:\n// 0: dense AND\n// 1: star per slice (stable hubs)\n// 2: min edge-cover per slice\n// 3: star per slice with global hubs (try to maximize vertical continuity)\nstatic vector<uint8_t> build_occ(int D,\n                                 const vector<string>& f,\n                                 const vector<string>& r,\n                                 int type) {\n    vector<vector<int>> X(D), Y(D);\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) if (f[z][x] == '1') X[z].push_back(x);\n        for (int y = 0; y < D; y++) if (r[z][y] == '1') Y[z].push_back(y);\n    }\n\n    vector<uint8_t> occ(D * D * D, 0);\n\n    if (type == 0) {\n        for (int z = 0; z < D; z++)\n            for (int x : X[z])\n                for (int y : Y[z])\n                    occ[idx3(D, x, y, z)] = 1;\n    } else if (type == 1) {\n        vector<int> x0 = choose_stable_sequence(X);\n        vector<int> y0 = choose_stable_sequence(Y);\n        for (int z = 0; z < D; z++) {\n            for (int x : X[z]) occ[idx3(D, x, y0[z], z)] = 1;\n            for (int y : Y[z]) occ[idx3(D, x0[z], y, z)] = 1;\n        }\n    } else if (type == 2) {\n        for (int z = 0; z < D; z++) {\n            auto &xs = X[z], &ys = Y[z];\n            int nx = (int)xs.size(), ny = (int)ys.size();\n            if (nx >= ny) {\n                for (int j = 0; j < ny; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = ny; j < nx; j++) occ[idx3(D, xs[j], ys[0], z)] = 1;\n            } else {\n                for (int j = 0; j < nx; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = nx; j < ny; j++) occ[idx3(D, xs[0], ys[j], z)] = 1;\n            }\n        }\n    } else { // type == 3\n        int gx = choose_global_hub(X, D);\n        int gy = choose_global_hub(Y, D);\n        for (int z = 0; z < D; z++) {\n            int xhub = gx, yhub = gy;\n            // If global hub not available in this slice, fall back.\n            if (find(X[z].begin(), X[z].end(), xhub) == X[z].end()) xhub = X[z][0];\n            if (find(Y[z].begin(), Y[z].end(), yhub) == Y[z].end()) yhub = Y[z][0];\n\n            for (int x : X[z]) occ[idx3(D, x, yhub, z)] = 1;\n            for (int y : Y[z]) occ[idx3(D, xhub, y, z)] = 1;\n        }\n    }\n    return occ;\n}\n\n// Greedy feasibility test: can we pack all item lengths into bins with capacities=seg lengths,\n// using \"smallest capacity that fits\" rule.\nstatic int pack_fail_len(int D, const vector<int>& items, const vector<int>& bins) {\n    int cntBin[15] = {};\n    for (int c : bins) cntBin[c]++;\n\n    // items are processed in non-increasing order\n    vector<int> sorted = items;\n    sort(sorted.begin(), sorted.end(), greater<int>());\n\n    for (int L : sorted) {\n        int c = -1;\n        for (int cap = L; cap <= D; cap++) {\n            if (cntBin[cap] > 0) { c = cap; break; }\n        }\n        if (c == -1) return L;\n        cntBin[c]--;\n        int r = c - L;\n        if (r > 0) cntBin[r]++;\n    }\n    return 0;\n}\n\n// Make shared pieces by starting from whole segments of the smaller object and splitting until packable.\nstatic vector<Piece> make_shared_pieces(int D,\n                                       const vector<Segment>& segSmall,\n                                       const vector<int>& binsLargeLens) {\n    vector<Piece> pcs;\n    pcs.reserve(4096);\n    for (int i = 0; i < (int)segSmall.size(); i++) {\n        pcs.push_back(Piece{i, 0, segSmall[i].len});\n    }\n\n    int maxCap = 0;\n    for (int c : binsLargeLens) maxCap = max(maxCap, c);\n\n    // Splitting loop\n    int it = 0;\n    while (true) {\n        vector<int> items;\n        items.reserve(pcs.size());\n        for (auto &p : pcs) items.push_back(p.len);\n\n        int fail = pack_fail_len(D, items, binsLargeLens);\n        if (fail == 0) break;\n\n        // find a piece with len == fail (or any longest if not found)\n        int pos = -1;\n        for (int i = 0; i < (int)pcs.size(); i++) {\n            if (pcs[i].len == fail) { pos = i; break; }\n        }\n        if (pos == -1) {\n            pos = 0;\n            for (int i = 1; i < (int)pcs.size(); i++) if (pcs[i].len > pcs[pos].len) pos = i;\n        }\n\n        int L = pcs[pos].len;\n        if (L <= 1) break; // should not happen if total volume condition holds\n\n        // Balanced split tends to minimize penalty increase.\n        int a = L / 2;\n        int b = L - a;\n\n        Piece p = pcs[pos];\n        pcs[pos] = Piece{p.segId, p.off, a};\n        pcs.push_back(Piece{p.segId, p.off + a, b});\n\n        // hard safety to avoid pathological loops (should never trigger)\n        if (++it > 10000) break;\n        // Additional: if L > maxCap, we will keep splitting until it fits; loop handles it naturally.\n        (void)maxCap;\n    }\n    return pcs;\n}\n\nstatic long double penalty_sum_inv(const vector<Piece>& pcs) {\n    long double s = 0.0L;\n    for (auto &p : pcs) s += 1.0L / (long double)p.len;\n    return s;\n}\n\nstatic void fill_piece(int D, vector<int>& b, const Segment& seg, const Piece& pc, int id) {\n    int dx = 0, dy = 0, dz = 0;\n    if (seg.axis == 0) dx = 1;\n    else if (seg.axis == 1) dy = 1;\n    else dz = 1;\n\n    for (int t = 0; t < pc.len; t++) {\n        int x = seg.x + dx * (pc.off + t);\n        int y = seg.y + dy * (pc.off + t);\n        int z = seg.z + dz * (pc.off + t);\n        b[idx3(D, x, y, z)] = id;\n    }\n}\n\n// Pack given shared pieces into large segments, producing placements (same order as shared list).\nstatic vector<Piece> pack_into_large(int D,\n                                    const vector<Segment>& segLarge,\n                                    const vector<Piece>& sharedSortedByLen,\n                                    vector<Piece>& uniqueOut) {\n    int nSeg = (int)segLarge.size();\n    vector<int> used(nSeg, 0), rem(nSeg, 0);\n    vector<vector<int>> bucket(D + 1);\n    for (int i = 0; i < nSeg; i++) {\n        rem[i] = segLarge[i].len;\n        if (rem[i] > 0) bucket[rem[i]].push_back(i);\n    }\n\n    vector<Piece> placed;\n    placed.reserve(sharedSortedByLen.size());\n\n    for (auto &sp : sharedSortedByLen) {\n        int L = sp.len;\n        int chosen = -1;\n        int cap = -1;\n        for (int c = L; c <= D; c++) {\n            if (!bucket[c].empty()) { cap = c; chosen = bucket[c].back(); bucket[c].pop_back(); break; }\n        }\n        // Feasibility was checked, so chosen should exist.\n        if (chosen == -1) {\n            // fallback (shouldn't happen): put nowhere\n            placed.push_back(Piece{0, 0, L});\n            continue;\n        }\n        int off = used[chosen];\n        placed.push_back(Piece{chosen, off, L});\n        used[chosen] += L;\n        rem[chosen] = cap - L;\n        if (rem[chosen] > 0) bucket[rem[chosen]].push_back(chosen);\n    }\n\n    // Unique tails\n    uniqueOut.clear();\n    for (int i = 0; i < nSeg; i++) {\n        if (rem[i] > 0) uniqueOut.push_back(Piece{i, used[i], rem[i]});\n    }\n    return placed;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n    vector<string> f[2], r[2];\n    for (int i = 0; i < 2; i++) {\n        f[i].resize(D);\n        r[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> f[i][z];\n        for (int z = 0; z < D; z++) cin >> r[i][z];\n    }\n\n    const int S = 4; // construction types\n    vector<uint8_t> occ[2][S];\n    long long vol[2][S];\n\n    for (int i = 0; i < 2; i++) {\n        for (int s = 0; s < S; s++) {\n            occ[i][s] = build_occ(D, f[i], r[i], s);\n            vol[i][s] = volume_of(occ[i][s]);\n        }\n    }\n\n    // Precompute segments for each (obj, construction, axis)\n    vector<Segment> segs[2][S][3];\n    vector<int> segLens[2][S][3];\n    for (int i = 0; i < 2; i++) for (int s = 0; s < S; s++) for (int a = 0; a < 3; a++) {\n        segs[i][s][a] = extract_segments(D, occ[i][s], a);\n        segLens[i][s][a].reserve(segs[i][s][a].size());\n        for (auto &sg : segs[i][s][a]) segLens[i][s][a].push_back(sg.len);\n    }\n\n    struct BestPlan {\n        int s0=-1, s1=-1, a0=-1, a1=-1;\n        int smallObj=0; // which object is treated as smaller and fully shared\n        long double cost = 1e100L;\n    } best;\n\n    auto eval_dir = [&](int s0, int a0, int s1, int a1, int smallObj)->long double {\n        // smallObj==0 means obj0 fully shared, pack its pieces into obj1\n        int bigObj = 1 - smallObj;\n        const auto& segSmall = segs[smallObj][(smallObj==0? s0:s1)][(smallObj==0? a0:a1)];\n        const auto& segLarge = segs[bigObj][(bigObj==0? s0:s1)][(bigObj==0? a0:a1)];\n\n        long long vSmall = 0, vLarge = 0;\n        for (auto &sg : segSmall) vSmall += sg.len;\n        for (auto &sg : segLarge) vLarge += sg.len;\n        if (vSmall > vLarge) return 1e100L; // not allowed for this direction\n\n        vector<int> binsLarge;\n        binsLarge.reserve(segLarge.size());\n        for (auto &sg : segLarge) binsLarge.push_back(sg.len);\n\n        auto pcs = make_shared_pieces(D, segSmall, binsLarge);\n        long double pen = penalty_sum_inv(pcs);\n        return (long double)(vLarge - vSmall) + pen;\n    };\n\n    for (int s0 = 0; s0 < S; s0++) for (int s1 = 0; s1 < S; s1++) {\n        for (int a0 = 0; a0 < 3; a0++) for (int a1 = 0; a1 < 3; a1++) {\n            long long v0 = vol[0][s0];\n            long long v1 = vol[1][s1];\n            if (v0 <= v1) {\n                long double c = eval_dir(s0,a0,s1,a1,0);\n                if (c < best.cost) best = {s0,s1,a0,a1,0,c};\n            }\n            if (v1 <= v0) {\n                long double c = eval_dir(s0,a0,s1,a1,1);\n                if (c < best.cost) best = {s0,s1,a0,a1,1,c};\n            }\n        }\n    }\n\n    // Reconstruct using best plan\n    int s0 = best.s0, s1 = best.s1, a0 = best.a0, a1 = best.a1;\n    int smallObj = best.smallObj;\n    int largeObj = 1 - smallObj;\n\n    const auto& seg0 = segs[0][s0][a0];\n    const auto& seg1 = segs[1][s1][a1];\n\n    const auto& segSmall = (smallObj==0 ? seg0 : seg1);\n    const auto& segLarge = (largeObj==0 ? seg0 : seg1);\n\n    vector<int> binsLarge;\n    binsLarge.reserve(segLarge.size());\n    for (auto &sg : segLarge) binsLarge.push_back(sg.len);\n\n    vector<Piece> pcsSmall = make_shared_pieces(D, segSmall, binsLarge);\n\n    // Sort shared pieces by length descending for better packing and smaller penalty labels\n    vector<int> ord(pcsSmall.size());\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int i, int j){\n        if (pcsSmall[i].len != pcsSmall[j].len) return pcsSmall[i].len > pcsSmall[j].len;\n        if (pcsSmall[i].segId != pcsSmall[j].segId) return pcsSmall[i].segId < pcsSmall[j].segId;\n        return pcsSmall[i].off < pcsSmall[j].off;\n    });\n\n    vector<Piece> sharedSmallSorted;\n    sharedSmallSorted.reserve(pcsSmall.size());\n    for (int id : ord) sharedSmallSorted.push_back(pcsSmall[id]);\n\n    vector<Piece> uniqueLarge;\n    vector<Piece> sharedLargePlaced = pack_into_large(D, segLarge, sharedSmallSorted, uniqueLarge);\n\n    int n_shared = (int)sharedSmallSorted.size();\n    int n_unique = (int)uniqueLarge.size();\n    int n = n_shared + n_unique;\n\n    vector<int> b[2];\n    b[0].assign(D*D*D, 0);\n    b[1].assign(D*D*D, 0);\n\n    int curId = 1;\n    for (int i = 0; i < n_shared; i++, curId++) {\n        if (smallObj == 0) {\n            fill_piece(D, b[0], segSmall[sharedSmallSorted[i].segId], sharedSmallSorted[i], curId);\n            fill_piece(D, b[1], segLarge[sharedLargePlaced[i].segId], sharedLargePlaced[i], curId);\n        } else {\n            fill_piece(D, b[1], segSmall[sharedSmallSorted[i].segId], sharedSmallSorted[i], curId);\n            fill_piece(D, b[0], segLarge[sharedLargePlaced[i].segId], sharedLargePlaced[i], curId);\n        }\n    }\n    for (int i = 0; i < n_unique; i++, curId++) {\n        if (largeObj == 0) {\n            fill_piece(D, b[0], segLarge[uniqueLarge[i].segId], uniqueLarge[i], curId);\n        } else {\n            fill_piece(D, b[1], segLarge[uniqueLarge[i].segId], uniqueLarge[i], curId);\n        }\n    }\n\n    cout << n << \"\\n\";\n    for (int i = 0; i < D*D*D; i++) {\n        if (i) cout << ' ';\n        cout << b[0][i];\n    }\n    cout << \"\\n\";\n    for (int i = 0; i < D*D*D; i++) {\n        if (i) cout << ' ';\n        cout << b[1][i];\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge {\n    int u, v;\n    long long w;\n};\n\nstatic inline int ceil_sqrt_ll(long long x) {\n    if (x <= 0) return 0;\n    long long r = (long long)floor(sqrt((long double)x));\n    while (r * r < x) ++r;\n    while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n    return (int)r;\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool merge(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a; sz[a]+=sz[b];\n        return true;\n    }\n};\n\nstruct Connector {\n    int N, M;\n    vector<Edge> edges;\n    vector<vector<tuple<int,long long,int>>> g; // to, w, edgeId\n\n    vector<vector<long long>> dist;  // N x N\n    vector<vector<int>> prevV;       // N x N\n    vector<vector<int>> prevE;       // N x N\n\n    vector<int> usedStamp; // size M\n    int stamp = 1;\n\n    // for pruning marking (avoid allocations)\n    vector<int> remStamp; // size M\n    int remCurStamp = 1;\n\n    Connector(int N_, int M_, const vector<Edge>& edges_)\n        : N(N_), M(M_), edges(edges_), g(N),\n          dist(N, vector<long long>(N, (1LL<<62))),\n          prevV(N, vector<int>(N, -1)),\n          prevE(N, vector<int>(N, -1)),\n          usedStamp(M, 0),\n          remStamp(M, 0) {\n\n        for (int i = 0; i < M; i++) {\n            auto &e = edges[i];\n            g[e.u].push_back({e.v, e.w, i});\n            g[e.v].push_back({e.u, e.w, i});\n        }\n        all_pairs_dijkstra();\n    }\n\n    void all_pairs_dijkstra() {\n        for (int s = 0; s < N; s++) {\n            auto &ds = dist[s];\n            auto &pv = prevV[s];\n            auto &pe = prevE[s];\n            fill(ds.begin(), ds.end(), (1LL<<62));\n            fill(pv.begin(), pv.end(), -1);\n            fill(pe.begin(), pe.end(), -1);\n\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            ds[s] = 0;\n            pv[s] = s;\n            pe[s] = -1;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [dcur, v] = pq.top(); pq.pop();\n                if (dcur != ds[v]) continue;\n                for (auto [to, w, id] : g[v]) {\n                    long long nd = dcur + w;\n                    if (nd < ds[to]) {\n                        ds[to] = nd;\n                        pv[to] = v;\n                        pe[to] = id;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n        }\n    }\n\n    // Build candidate edge set by:\n    // 1) MST on terminals in metric closure (Prim)\n    // 2) expand each MST edge to a shortest path and take union\n    // 3) ensure all terminals reachable from 0 by adding shortest paths 0->t when needed\n    // Returns list of candidate original edge IDs.\n    vector<int> build_candidate_edges(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked;\n        marked.reserve(M);\n\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n\n        if ((int)terminals.size() <= 1) return marked;\n\n        // Prim over terminals (complete graph with dist[][])\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i]; v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) {\n                    key[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n\n        // expand MST edges into shortest paths using prev arrays\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        // reachability from 0 on marked edges\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true;\n        dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) {\n                    reach[to] = true;\n                    dq.push_back(to);\n                }\n            }\n        }\n\n        // ensure each terminal reachable by adding shortest path from 0 if needed\n        for (int t : terminals) {\n            if (reach[t]) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        return marked;\n    }\n\n    // Improved cable cost:\n    // - build candidate edges by expanded metric MST\n    // - run Kruskal MST on candidate subgraph to remove cycles\n    // - prune non-terminal leaves\n    long long steiner_cost(const vector<int>& terminals) {\n        if (terminals.size() <= 1) return 0;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n\n        vector<int> cand = build_candidate_edges(terminals);\n        if (cand.empty()) return 0;\n\n        // Kruskal on candidate edges (gives a forest; terminals should end up connected)\n        vector<int> candSorted = cand;\n        sort(candSorted.begin(), candSorted.end(),\n             [&](int a, int b){ return edges[a].w < edges[b].w; });\n\n        DSU dsu(N);\n        vector<int> treeEdges;\n        treeEdges.reserve(candSorted.size());\n        for (int eid : candSorted) {\n            if (dsu.merge(edges[eid].u, edges[eid].v)) treeEdges.push_back(eid);\n        }\n\n        // build adjacency of forest\n        vector<vector<pair<int,int>>> adj(N);\n        vector<int> deg(N, 0);\n        for (int eid : treeEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            adj[u].push_back({v, eid});\n            adj[v].push_back({u, eid});\n            deg[u]++; deg[v]++;\n        }\n\n        // prune non-terminal leaves\n        int curRemStamp = remCurStamp++;\n        auto isRemoved = [&](int eid)->bool { return remStamp[eid] == curRemStamp; };\n        auto setRemoved = [&](int eid){ remStamp[eid] = curRemStamp; };\n\n        deque<int> q;\n        for (int i = 0; i < N; i++) {\n            if (!isTerm[i] && deg[i] == 1) q.push_back(i);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n            // find its only alive edge\n            int to = -1, eid = -1;\n            for (auto [nx, id] : adj[v]) {\n                if (!isRemoved(id)) { to = nx; eid = id; break; }\n            }\n            if (eid == -1) { deg[v] = 0; continue; }\n            setRemoved(eid);\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        long long cost = 0;\n        for (int eid : treeEdges) if (!isRemoved(eid)) cost += edges[eid].w;\n        return cost;\n    }\n\n    vector<char> steiner_build(const vector<int>& terminals) {\n        vector<char> on(M, 0);\n        if (terminals.size() <= 1) return on;\n\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n\n        vector<int> cand = build_candidate_edges(terminals);\n        if (cand.empty()) return on;\n\n        vector<int> candSorted = cand;\n        sort(candSorted.begin(), candSorted.end(),\n             [&](int a, int b){ return edges[a].w < edges[b].w; });\n\n        DSU dsu(N);\n        vector<int> treeEdges;\n        treeEdges.reserve(candSorted.size());\n        for (int eid : candSorted) {\n            if (dsu.merge(edges[eid].u, edges[eid].v)) treeEdges.push_back(eid);\n        }\n\n        vector<vector<pair<int,int>>> adj(N);\n        vector<int> deg(N, 0);\n        for (int eid : treeEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            adj[u].push_back({v, eid});\n            adj[v].push_back({u, eid});\n            deg[u]++; deg[v]++;\n        }\n\n        int curRemStamp = remCurStamp++;\n        auto isRemoved = [&](int eid)->bool { return remStamp[eid] == curRemStamp; };\n        auto setRemoved = [&](int eid){ remStamp[eid] = curRemStamp; };\n\n        deque<int> q;\n        for (int i = 0; i < N; i++) if (!isTerm[i] && deg[i] == 1) q.push_back(i);\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n            int to = -1, eid = -1;\n            for (auto [nx, id] : adj[v]) {\n                if (!isRemoved(id)) { to = nx; eid = id; break; }\n            }\n            if (eid == -1) { deg[v] = 0; continue; }\n            setRemoved(eid);\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        for (int eid : treeEdges) if (!isRemoved(eid)) on[eid] = 1;\n        return on;\n    }\n};\n\n// RNG: xorshift64\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct SAState {\n    int N, K;\n    const vector<int>* dist2;                // K*N\n    const vector<array<int,100>>* order;     // K\n    Connector* conn;\n\n    static constexpr int D2_LIMIT = 5000 * 5000;\n\n    vector<char> active; // whether station can be used as center\n    vector<int> owner;   // resident -> station\n    vector<int> dOwn;    // resident -> dist2 to owner\n\n    // doubly-linked resident lists per station\n    vector<int> head;     // station -> resident\n    vector<int> rprev, rnext; // per resident\n\n    vector<multiset<int>> ms; // per station: multiset of dist2 values\n    vector<int> P;            // per station\n    long long radioCost = 0;\n    long long edgeCost = 0;\n    long long totalCost = 0;\n\n    inline int d2(int k, int i) const { return (*dist2)[k*N + i]; }\n\n    void list_remove(int k) {\n        int s = owner[k];\n        int pv = rprev[k], nx = rnext[k];\n        if (pv != -1) rnext[pv] = nx;\n        else head[s] = nx;\n        if (nx != -1) rprev[nx] = pv;\n        rprev[k] = rnext[k] = -1;\n    }\n    void list_add(int k, int s) {\n        int h = head[s];\n        head[s] = k;\n        rprev[k] = -1;\n        rnext[k] = h;\n        if (h != -1) rprev[h] = k;\n    }\n\n    void rebuild_from_active_nearest() {\n        // clear\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        active[0] = 1;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            for (int idx = 0; idx < N; idx++) {\n                int v = (*order)[k][idx];\n                if (active[v]) { chosen = v; break; }\n            }\n            if (chosen < 0) chosen = 0;\n            int dd = d2(k, chosen);\n            // if dd > D2_LIMIT, coverage impossible with this active set\n            owner[k] = chosen;\n            dOwn[k] = dd;\n            list_add(k, chosen);\n            ms[chosen].insert(dd);\n        }\n\n        // deactivate empty (except 0) to reduce useless SA space\n        for (int i = 1; i < N; i++) if (ms[i].empty()) active[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            int p = 0;\n            if (!ms[i].empty()) p = ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        vector<int> terminals;\n        terminals.reserve(N);\n        terminals.push_back(0);\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) terminals.push_back(i);\n        edgeCost = conn->steiner_cost(terminals);\n        totalCost = radioCost + edgeCost;\n    }\n\n    vector<int> terminals() const {\n        vector<int> t;\n        t.reserve(N);\n        t.push_back(0);\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) t.push_back(i);\n        return t;\n    }\n\n    struct Log {\n        vector<tuple<int,int,int>> moved; // (resident, oldOwner, oldDist)\n        vector<pair<int,char>> flipped;   // (station, oldActive)\n        vector<pair<int,int>> oldP;       // (station, oldP)\n        vector<int> touchedStations;\n        long long oldRadio, oldEdge, oldTotal;\n    };\n\n    void touch_station(int s, vector<char>& touchedFlag, Log& log) {\n        if (touchedFlag[s]) return;\n        touchedFlag[s] = 1;\n        log.touchedStations.push_back(s);\n        log.oldP.push_back({s, P[s]});\n    }\n\n    void move_resident(int k, int newS, vector<char>& touchedFlag, Log& log) {\n        int oldS = owner[k];\n        if (oldS == newS) return;\n        int oldD = dOwn[k];\n        log.moved.push_back({k, oldS, oldD});\n\n        touch_station(oldS, touchedFlag, log);\n        touch_station(newS, touchedFlag, log);\n\n        // multiset updates\n        auto it = ms[oldS].find(oldD);\n        if (it != ms[oldS].end()) ms[oldS].erase(it);\n        int nd = d2(k, newS);\n        ms[newS].insert(nd);\n\n        // list updates\n        list_remove(k);\n        owner[k] = newS;\n        dOwn[k] = nd;\n        list_add(k, newS);\n    }\n\n    // find nearest active station (excluding optionally one station ex=-1)\n    int nearest_active(int k, int ex) const {\n        for (int idx = 0; idx < N; idx++) {\n            int v = (*order)[k][idx];\n            if (!active[v]) continue;\n            if (v == ex) continue;\n            int dd = d2(k, v);\n            if (dd <= D2_LIMIT) return v;\n            // note: order is by distance; once dd>limit, later are also >limit\n            // BUT because of rounding ties etc, still safe to early stop:\n            // We'll just continue for correctness (N=100 small).\n        }\n        return -1;\n    }\n\n    bool apply_remove(int v, Log& log, vector<char>& touchedFlag) {\n        if (v == 0 || !active[v]) return false;\n        // flip active off\n        log.flipped.push_back({v, active[v]});\n        active[v] = 0;\n\n        // collect residents currently in v\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, touchedFlag, log);\n        }\n        return true;\n    }\n\n    bool apply_add(int u, Log& log, vector<char>& touchedFlag) {\n        if (active[u]) return false;\n        log.flipped.push_back({u, active[u]});\n        active[u] = 1;\n\n        // for each resident, if u is better than current owner by (dist, index), move\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) {\n                move_resident(k, u, touchedFlag, log);\n            }\n        }\n        return true;\n    }\n\n    bool apply_swap(int v, int u, Log& log, vector<char>& touchedFlag) {\n        if (v == 0 || !active[v] || active[u]) return false;\n        log.flipped.push_back({v, active[v]});\n        active[v] = 0;\n        log.flipped.push_back({u, active[u]});\n        active[u] = 1;\n\n        // reassign residents of v\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, touchedFlag, log);\n        }\n\n        // now u may attract residents\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) {\n                move_resident(k, u, touchedFlag, log);\n            }\n        }\n        return true;\n    }\n\n    void finalize_cost_after_move(Log& log) {\n        // update radioCost incrementally from old using touched stations\n        radioCost = log.oldRadio;\n        for (int s : log.touchedStations) {\n            int oldp = 0;\n            // find oldp\n            // (touchedStations is small; linear search ok)\n            // but we already stored oldP list in same order:\n        }\n        // better: build map station->oldp with array\n        vector<int> oldpArr(N, -1);\n        for (auto [s, op] : log.oldP) oldpArr[s] = op;\n\n        for (int s : log.touchedStations) {\n            int oldp = oldpArr[s];\n            int newp = 0;\n            if (!ms[s].empty()) newp = ceil_sqrt_ll(*ms[s].rbegin());\n            if (newp > 5000) newp = 5000;\n            P[s] = newp;\n            radioCost += 1LL * newp * newp - 1LL * oldp * oldp;\n        }\n\n        // edge cost depends on which stations are non-empty\n        edgeCost = conn->steiner_cost(terminals());\n        totalCost = radioCost + edgeCost;\n    }\n\n    void undo(Log& log) {\n        // undo resident moves in reverse\n        for (int i = (int)log.moved.size() - 1; i >= 0; i--) {\n            auto [k, oldS, oldD] = log.moved[i];\n            int curS = owner[k];\n            int curD = dOwn[k];\n\n            // multiset revert\n            auto it = ms[curS].find(curD);\n            if (it != ms[curS].end()) ms[curS].erase(it);\n            ms[oldS].insert(oldD);\n\n            // list revert\n            list_remove(k);\n            owner[k] = oldS;\n            dOwn[k] = oldD;\n            list_add(k, oldS);\n        }\n\n        // undo active flips\n        for (int i = (int)log.flipped.size() - 1; i >= 0; i--) {\n            auto [s, oldA] = log.flipped[i];\n            active[s] = oldA;\n        }\n\n        // restore P\n        for (auto [s, op] : log.oldP) P[s] = op;\n\n        radioCost = log.oldRadio;\n        edgeCost  = log.oldEdge;\n        totalCost = log.oldTotal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n    vector<Edge> edges(M);\n    for (int j = 0; j < M; j++) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n    }\n\n    vector<int> a(K), b(K);\n    for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n    // Precompute squared distances resident->station and resident order by distance\n    vector<int> dist2((size_t)K * N);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) {\n            long long dx = (long long)x[i] - a[k];\n            long long dy = (long long)y[i] - b[k];\n            dist2[k*N + i] = (int)(dx*dx + dy*dy);\n        }\n    }\n\n    vector<array<int,100>> order(K);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) order[k][i] = i;\n        sort(order[k].begin(), order[k].end(), [&](int i, int j){\n            int di = dist2[k*N + i];\n            int dj = dist2[k*N + j];\n            if (di != dj) return di < dj;\n            return i < j;\n        });\n    }\n\n    Connector conn(N, M, edges);\n\n    SAState st;\n    st.N = N; st.K = K;\n    st.dist2 = &dist2;\n    st.order = &order;\n    st.conn = &conn;\n\n    st.active.assign(N, 1); // start all active, will shrink after rebuild\n    st.rebuild_from_active_nearest();\n\n    // Simulated annealing\n    RNG rng(123456789);\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n    const double TL = 1.90;\n\n    vector<char> bestActive = st.active;\n    long long bestCost = st.totalCost;\n\n    // temperature schedule tuned to typical delta scale (~1e7..1e9)\n    const double T0 = 2e9;\n    const double T1 = 2e6;\n\n    int iter = 0;\n    while (elapsed() < TL) {\n        iter++;\n        double t = elapsed() / TL;\n        double temp = T0 * pow(T1 / T0, t);\n\n        SAState::Log log;\n        log.oldRadio = st.radioCost;\n        log.oldEdge  = st.edgeCost;\n        log.oldTotal = st.totalCost;\n        vector<char> touchedFlag(N, 0);\n\n        // choose operation\n        double r = rng.nextDouble();\n        bool ok = false;\n\n        if (r < 0.45) { // remove\n            int v = -1;\n            for (int tries = 0; tries < 20; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (st.active[cand] && !st.ms[cand].empty()) { v = cand; break; }\n            }\n            if (v == -1) continue;\n            ok = st.apply_remove(v, log, touchedFlag);\n        } else if (r < 0.80) { // add\n            int u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (!st.active[cand]) { u = cand; break; }\n            }\n            if (u == -1) continue;\n            ok = st.apply_add(u, log, touchedFlag);\n        } else { // swap\n            int v = -1, u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int candV = rng.nextInt(1, N-1);\n                if (st.active[candV] && !st.ms[candV].empty()) { v = candV; break; }\n            }\n            for (int tries = 0; tries < 30; tries++) {\n                int candU = rng.nextInt(1, N-1);\n                if (!st.active[candU]) { u = candU; break; }\n            }\n            if (v == -1 || u == -1) continue;\n            ok = st.apply_swap(v, u, log, touchedFlag);\n        }\n\n        if (!ok) {\n            st.undo(log);\n            continue;\n        }\n\n        st.finalize_cost_after_move(log);\n\n        long long delta = st.totalCost - log.oldTotal;\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(-(double)delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (!accept) {\n            st.undo(log);\n            continue;\n        }\n\n        // keep best\n        if (st.totalCost < bestCost) {\n            bestCost = st.totalCost;\n            bestActive = st.active;\n        }\n    }\n\n    // Rebuild final state from bestActive (nearest assignment), then output\n    st.active = bestActive;\n    st.rebuild_from_active_nearest();\n\n    // Construct final terminals and final edge set\n    vector<int> terminals = st.terminals();\n    vector<char> on = conn.steiner_build(terminals);\n\n    // Output P_1..P_N\n    for (int i = 0; i < N; i++) {\n        int pi = st.P[i];\n        if (pi < 0) pi = 0;\n        if (pi > 5000) pi = 5000;\n        cout << pi << (i+1==N?'\\n':' ');\n    }\n    // Output B_1..B_M\n    for (int j = 0; j < M; j++) {\n        cout << (int)on[j] << (j+1==M?'\\n':' ');\n    }\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int M = N * (N + 1) / 2;\nstatic constexpr int LIMIT = 10000;\n\nstruct PQEdge {\n    int diff;\n    int p, c; // parent, child (directed downward)\n    bool operator<(PQEdge const& other) const {\n        return diff < other.diff; // max-heap by diff\n    }\n};\n\nstruct Solver {\n    // value at node id\n    array<int, M> a{};\n    // position (node id) for each value 0..M-1\n    array<int, M> pos{};\n\n    // id -> (x,y)\n    array<int, M> X{}, Y{};\n    // parents/children by heap edges (not full 6-neighborhood)\n    array<array<int, 2>, M> par{};\n    array<int, M> parCnt{};\n    array<array<int, 2>, M> ch{};\n    array<int, M> chCnt{};\n\n    vector<array<int,4>> ops;\n\n    priority_queue<PQEdge> pq;\n\n    static int id(int x, int y) {\n        return x * (x + 1) / 2 + y;\n    }\n\n    void build_coords_and_graph() {\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v = id(x,y);\n                X[v] = x; Y[v] = y;\n\n                // parents\n                parCnt[v] = 0;\n                if (x > 0) {\n                    if (y > 0) par[v][parCnt[v]++] = id(x-1, y-1);\n                    if (y < x) par[v][parCnt[v]++] = id(x-1, y);\n                }\n\n                // children\n                chCnt[v] = 0;\n                if (x + 1 < N) {\n                    ch[v][chCnt[v]++] = id(x+1, y);\n                    ch[v][chCnt[v]++] = id(x+1, y+1);\n                }\n            }\n        }\n    }\n\n    inline void try_push_edge(int p, int c) {\n        if (a[p] > a[c]) pq.push(PQEdge{a[p] - a[c], p, c});\n    }\n\n    inline void add_incident_edges(int u) {\n        // u as parent\n        for (int i = 0; i < chCnt[u]; i++) {\n            int v = ch[u][i];\n            try_push_edge(u, v);\n        }\n        // u as child\n        for (int i = 0; i < parCnt[u]; i++) {\n            int p = par[u][i];\n            try_push_edge(p, u);\n        }\n    }\n\n    bool do_swap(int u, int v) {\n        if ((int)ops.size() >= LIMIT) return false;\n\n        ops.push_back({X[u], Y[u], X[v], Y[v]});\n\n        int au = a[u], av = a[v];\n        swap(a[u], a[v]);\n\n        pos[au] = v;\n        pos[av] = u;\n\n        add_incident_edges(u);\n        add_incident_edges(v);\n        return true;\n    }\n\n    void bubble_up(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestP = -1;\n            for (int i = 0; i < parCnt[u]; i++) {\n                int p = par[u][i];\n                if (a[p] > a[u]) {\n                    if (bestP == -1 || a[p] > a[bestP]) bestP = p;\n                }\n            }\n            if (bestP == -1) break;\n            if (!do_swap(bestP, u)) break;\n            u = bestP;\n        }\n    }\n\n    void bubble_down(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestC = -1;\n            for (int i = 0; i < chCnt[u]; i++) {\n                int c = ch[u][i];\n                if (a[u] > a[c]) {\n                    if (bestC == -1 || a[c] < a[bestC]) bestC = c;\n                }\n            }\n            if (bestC == -1) break;\n            if (!do_swap(u, bestC)) break;\n            u = bestC;\n        }\n    }\n\n    int count_violations() const {\n        int E = 0;\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = id(x,y);\n                int c1 = id(x+1,y);\n                int c2 = id(x+1,y+1);\n                if (a[p] > a[c1]) E++;\n                if (a[p] > a[c2]) E++;\n            }\n        }\n        return E;\n    }\n\n    void init_pq_all_violations() {\n        while (!pq.empty()) pq.pop();\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = id(x,y);\n                int c1 = id(x+1,y);\n                int c2 = id(x+1,y+1);\n                try_push_edge(p, c1);\n                try_push_edge(p, c2);\n            }\n        }\n    }\n\n    void solve() {\n        build_coords_and_graph();\n\n        // read input into a[]\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v;\n                cin >> v;\n                int node = id(x,y);\n                a[node] = v;\n                pos[v] = node;\n            }\n        }\n\n        init_pq_all_violations();\n\n        // Main loop: fix violations in order of largest (parent-child) difference.\n        // After a swap, locally bubble up/down to reduce future violations.\n        while (!pq.empty() && (int)ops.size() < LIMIT) {\n            auto e = pq.top(); pq.pop();\n            int p = e.p, c = e.c;\n            if (a[p] <= a[c]) continue; // stale\n            if (!do_swap(p, c)) break;\n\n            // After swap: smaller moved to p, larger moved to c.\n            bubble_up(p);\n            bubble_down(c);\n        }\n\n        // Safety: if somehow still violations and operations remain, restart PQ and continue.\n        // (Usually not needed, but cheap insurance.)\n        for (int rep = 0; rep < 2 && (int)ops.size() < LIMIT; rep++) {\n            if (count_violations() == 0) break;\n            init_pq_all_violations();\n            while (!pq.empty() && (int)ops.size() < LIMIT) {\n                auto e = pq.top(); pq.pop();\n                int p = e.p, c = e.c;\n                if (a[p] <= a[c]) continue;\n                if (!do_swap(p, c)) break;\n                bubble_up(p);\n                bubble_down(c);\n            }\n        }\n\n        // Output\n        cout << ops.size() << \"\\n\";\n        for (auto &op : ops) {\n            cout << op[0] << \" \" << op[1] << \" \" << op[2] << \" \" << op[3] << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    s.solve();\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct ArticulationResult {\n    vector<char> is_art;   // size V\n    vector<char> vis;      // reachable from root in current empty graph\n};\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    cin >> D >> N;\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    const int ei = 0, ej = (D - 1) / 2;\n    auto inside = [&](int i, int j) {\n        return 0 <= i && i < D && 0 <= j && j < D;\n    };\n    auto idx = [&](int i, int j) { return i * D + j; };\n    auto pos = [&](int v) { return pair<int,int>(v / D, v % D); };\n    const int root = idx(ei, ej);\n\n    const int M = D * D - 1 - N; // number of containers\n\n    // Precompute BFS distances on the static free-cell graph (ignoring containers).\n    const int V = D * D;\n    const int INF = 1e9;\n    vector<int> dist(V, INF);\n    {\n        queue<int> q;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                if (obstacle[ni][nj]) continue;\n                int u = idx(ni, nj);\n                if (dist[u] > dist[v] + 1) {\n                    dist[u] = dist[v] + 1;\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    // Build storable cells list and assign a global \"priority rank\".\n    vector<int> storable;\n    storable.reserve(M);\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == ei && j == ej) continue;\n        if (obstacle[i][j]) continue;\n        storable.push_back(idx(i, j));\n    }\n    sort(storable.begin(), storable.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        auto [ai, aj] = pos(a);\n        auto [bi, bj] = pos(b);\n        if (ai != bi) return ai < bi;\n        return aj < bj;\n    });\n\n    vector<int> rankv(V, -1);\n    for (int r = 0; r < (int)storable.size(); r++) rankv[storable[r]] = r;\n\n    vector<char> occupied(V, 0); // during placement: true if container already placed there\n    vector<int> label_at(V, -1); // final label at cell\n\n    auto is_empty_for_placement = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;     // entrance\n        return !occupied[v];\n    };\n\n    // Compute articulation points in current \"empty graph\" (for placement).\n    function<ArticulationResult()> compute_articulations = [&]() -> ArticulationResult {\n        vector<int> disc(V, -1), low(V, -1), parent(V, -1);\n        vector<char> is_art(V, 0), vis(V, 0);\n        int timer = 0;\n\n        function<void(int)> dfs = [&](int v) {\n            vis[v] = 1;\n            disc[v] = low[v] = timer++;\n            int child = 0;\n\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (!is_empty_for_placement(u)) continue;\n\n                if (disc[u] == -1) {\n                    parent[u] = v;\n                    child++;\n                    dfs(u);\n                    low[v] = min(low[v], low[u]);\n\n                    if (v != root && low[u] >= disc[v]) is_art[v] = 1;\n                } else if (u != parent[v]) {\n                    low[v] = min(low[v], disc[u]);\n                }\n            }\n\n            if (v == root && child > 1) is_art[v] = 1;\n        };\n\n        if (is_empty_for_placement(root)) dfs(root);\n\n        return {is_art, vis};\n    };\n\n    auto count_candidates_next = [&](int removed_cell) -> int {\n        occupied[removed_cell] = 1;\n        auto ar = compute_articulations();\n        int cnt = 0;\n        for (int v : storable) {\n            if (occupied[v]) continue;\n            if (!ar.vis[v]) continue;\n            if (!ar.is_art[v]) cnt++;\n        }\n        occupied[removed_cell] = 0;\n        return cnt;\n    };\n\n    // Placement phase (interactive).\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        auto ar = compute_articulations();\n\n        vector<int> cand;\n        cand.reserve(80);\n        for (int v : storable) {\n            if (occupied[v]) continue;\n            if (!ar.vis[v]) continue;        // should not happen if we keep connectivity\n            if (ar.is_art[v]) continue;      // removing would disconnect remaining empties\n            cand.push_back(v);\n        }\n\n        // Safety fallback: should never be empty, but just in case.\n        if (cand.empty()) {\n            // pick any reachable empty cell\n            for (int v : storable) if (!occupied[v] && ar.vis[v]) { cand.push_back(v); break; }\n        }\n\n        int best = cand[0];\n        long long bestScore = (1LL<<62);\n\n        for (int v : cand) {\n            int rc = rankv[v];\n            int assignCost = abs(rc - t);             // match label to cell priority\n            int flex = (step + 1 < M) ? count_candidates_next(v) : 0;\n\n            // Weighted score (assignment dominates; flex is tie-breaker-ish).\n            long long score = 100LL * assignCost - 1LL * flex;\n\n            // Small tie breaker: prefer farther cells if equal (often keeps core robust).\n            score = score * 100 + dist[v];\n\n            if (score < bestScore) {\n                bestScore = score;\n                best = v;\n            }\n        }\n\n        occupied[best] = 1;\n        label_at[best] = t;\n        auto [pi, pj] = pos(best);\n        cout << pi << ' ' << pj << '\\n' << flush;\n    }\n\n    // Removal phase (offline, after all placements).\n    vector<char> removed(V, 0); // false => still has container (except obstacles/entrance)\n    auto is_empty_for_removal_bfs = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;\n        // storable cells are occupied until removed\n        return removed[v];\n    };\n\n    for (int step = 0; step < M; step++) {\n        // BFS reachable empty cells\n        vector<char> vis(V, 0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_for_removal_bfs(u)) continue;\n                vis[u] = 1;\n                q.push(u);\n            }\n        }\n\n        // Find removable container with smallest label: occupied cell adjacent to reachable empty.\n        int bestCell = -1;\n        int bestLabel = INT_MAX;\n\n        for (int v : storable) {\n            if (removed[v]) continue; // already shipped\n            // reachable if adjacent to some visited empty cell\n            auto [i, j] = pos(v);\n            bool ok = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + di[dir], nj = j + dj[dir];\n                if (!inside(ni, nj)) continue;\n                int u = idx(ni, nj);\n                if (vis[u]) { ok = true; break; }\n            }\n            if (!ok) continue;\n\n            int lab = label_at[v];\n            if (lab < bestLabel) {\n                bestLabel = lab;\n                bestCell = v;\n            }\n        }\n\n        // Should always exist.\n        if (bestCell == -1) {\n            // Fallback: pick any remaining container adjacent to entrance area (shouldn't happen)\n            for (int v : storable) if (!removed[v]) { bestCell = v; break; }\n        }\n\n        removed[bestCell] = 1;\n        auto [qi, qj] = pos(bestCell);\n        cout << qi << ' ' << qj << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int DX[4] = {1, -1, 0, 0};\nstatic constexpr int DY[4] = {0, 0, 1, -1};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> orig(n, vector<int>(n));\n    for (int i = 0; i < n; i++)\n        for (int j = 0; j < n; j++)\n            cin >> orig[i][j];\n\n    const int C = m + 1; // 0..m\n\n    auto inside = [&](int i, int j) {\n        return (0 <= i && i < n && 0 <= j && j < n);\n    };\n    auto is_boundary = [&](int i, int j) {\n        return (i == 0 || i == n - 1 || j == 0 || j == n - 1);\n    };\n    auto idx = [&](int i, int j) { return i * n + j; };\n\n    // Required adjacency matrix (existence, not counts)\n    vector<vector<char>> req(C, vector<char>(C, 0));\n    vector<char> req0(C, 0);\n\n    // Non-zero adjacencies from original grid\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = orig[i][j];\n            if (i + 1 < n) {\n                int b = orig[i + 1][j];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n            if (j + 1 < n) {\n                int b = orig[i][j + 1];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n        }\n    }\n    // Adjacency with outside 0: boundary cells\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (!is_boundary(i, j)) continue;\n            int c = orig[i][j];\n            req[0][c] = req[c][0] = 1;\n            req0[c] = 1;\n        }\n    }\n\n    auto coastal = [&](int c) -> bool { return c > 0 && req0[c]; };\n    auto inland  = [&](int c) -> bool { return c > 0 && !req0[c]; };\n\n    // Current grid\n    vector<vector<int>> g = orig;\n\n    // Sizes\n    vector<int> sz(C, 0);\n    for (int i = 0; i < n; i++)\n        for (int j = 0; j < n; j++)\n            sz[g[i][j]]++;\n\n    // Edge counts between colors: store symmetric counts in upper triangle ec[min][max]\n    vector<vector<int>> ec(C, vector<int>(C, 0));\n    auto addEdge = [&](int u, int v, int delta) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        ec[u][v] += delta;\n    };\n    auto getEdge = [&](int u, int v) -> int {\n        if (u == v) return 0;\n        if (u > v) swap(u, v);\n        return ec[u][v];\n    };\n\n    // Initialize edge counts from current g\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = g[i][j];\n            if (i + 1 < n) addEdge(a, g[i + 1][j], +1);\n            if (j + 1 < n) addEdge(a, g[i][j + 1], +1);\n            if (i == 0) addEdge(0, a, +1);\n            if (i == n - 1) addEdge(0, a, +1);\n            if (j == 0) addEdge(0, a, +1);\n            if (j == n - 1) addEdge(0, a, +1);\n        }\n    }\n\n    // Connectivity helper for removing one cell of a color\n    vector<int> vis(n * n, 0);\n    int vis_stamp = 1;\n\n    auto connected_after_remove = [&](int i, int j, int c) -> bool {\n        // find a start neighbor of same color\n        int si = -1, sj = -1;\n        int same_deg = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == c) {\n                same_deg++;\n                if (si == -1) { si = ni; sj = nj; }\n            }\n        }\n        if (si == -1) return false;          // would isolate or remove last component\n        if (same_deg <= 1) return true;      // removing a leaf can't disconnect\n\n        int target = sz[c] - 1;\n        vis_stamp++;\n        deque<pair<int,int>> q;\n        q.push_back({si, sj});\n        vis[idx(si, sj)] = vis_stamp;\n        int cnt = 1;\n\n        while (!q.empty()) {\n            auto [x, y] = q.front(); q.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!inside(nx, ny)) continue;\n                if (nx == i && ny == j) continue;\n                if (g[nx][ny] != c) continue;\n                int id = idx(nx, ny);\n                if (vis[id] == vis_stamp) continue;\n                vis[id] = vis_stamp;\n                q.push_back({nx, ny});\n                cnt++;\n            }\n        }\n        return cnt == target;\n    };\n\n    // For legality: deleting to 0 must keep new 0 connected to outside (we keep it connected to existing 0/outside)\n    auto adjacent_to_zero_or_outside = [&](int i, int j) -> bool {\n        if (is_boundary(i, j)) return true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == 0) return true;\n        }\n        return false;\n    };\n\n    // Try apply recolor (old -> newc), maintaining legality at all times.\n    auto try_apply = [&](int i, int j, int newc) -> bool {\n        int old = g[i][j];\n        if (old == 0) return false;\n        if (old == newc) return false;\n\n        if (sz[old] <= 1) return false; // never remove last tile of a color\n\n        if (newc == 0) {\n            // Keep 0 connected: only expand from boundary or existing 0\n            if (!adjacent_to_zero_or_outside(i, j)) return false;\n        } else {\n            // Adding to an existing color: must touch that color to keep it connected (avoid creating a new component)\n            bool touch = false;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj) && g[ni][nj] == newc) { touch = true; break; }\n            }\n            if (!touch) return false;\n        }\n\n        // Connectivity of old after removal\n        if (!connected_after_remove(i, j, old)) return false;\n\n        // Build local edge-count deltas\n        int keys[16], vals[16], ksz = 0;\n        auto addDelta = [&](int u, int v, int delta) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            int key = u * C + v;\n            for (int t = 0; t < ksz; t++) {\n                if (keys[t] == key) { vals[t] += delta; return; }\n            }\n            keys[ksz] = key;\n            vals[ksz] = delta;\n            ksz++;\n        };\n\n        // For each incident edge of (i,j)\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n\n            if (old != d) addDelta(old, d, -1);\n            if (newc != d) addDelta(newc, d, +1);\n        }\n\n        // Check adjacency existence exactly matches req for affected pairs\n        for (int t = 0; t < ksz; t++) {\n            int key = keys[t];\n            int u = key / C;\n            int v = key % C;\n            int cur = getEdge(u, v);\n            int nxt = cur + vals[t];\n            if (nxt < 0) return false;\n            if (req[u][v]) {\n                if (nxt == 0) return false;\n            } else {\n                if (nxt != 0) return false;\n            }\n        }\n\n        // Apply edge updates\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addEdge(old, d, -1);\n            if (newc != d) addEdge(newc, d, +1);\n        }\n\n        // Apply grid and sizes\n        g[i][j] = newc;\n        sz[old]--;\n        if (newc > 0) sz[newc]++;\n\n        return true;\n    };\n\n    // Heuristic metric: inland\u2013coastal interface count change for recolor old->newc\n    auto delta_interface = [&](int i, int j, int old, int neu) -> int {\n        auto contrib = [&](int x, int y) -> int {\n            if (y == 0) return 0;\n            if (x == y) return 0;\n            bool fx = inland(x);\n            bool fy = inland(y);\n            return (fx ^ fy) ? 1 : 0;\n        };\n        int before = 0, after = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            before += contrib(old, d);\n            after  += contrib(neu, d);\n        }\n        return after - before;\n    };\n\n    // Candidate pools (allow duplicates; validate at pop-time)\n    vector<int> delCand, recCand;\n    delCand.reserve(n * n * 8);\n    recCand.reserve(n * n * 8);\n\n    for (int i = 0; i < n; i++)\n        for (int j = 0; j < n; j++)\n            if (is_boundary(i, j)) delCand.push_back(idx(i, j));\n\n    auto push_around = [&](int i, int j) {\n        for (int di = -1; di <= 1; di++) {\n            for (int dj = -1; dj <= 1; dj++) {\n                int x = i + di, y = j + dj;\n                if (!inside(x, y)) continue;\n                delCand.push_back(idx(x, y));\n                recCand.push_back(idx(x, y));\n            }\n        }\n        for (int k = 0; k < 4; k++) {\n            int x = i + DX[k], y = j + DY[k];\n            if (!inside(x, y)) continue;\n            delCand.push_back(idx(x, y));\n            recCand.push_back(idx(x, y));\n        }\n    };\n\n    // RNG\n    uint64_t seed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937 rng((uint32_t)seed);\n\n    Timer timer;\n    const double TL = 1.90;\n\n    // Main improvement loop: mix shrink (inland->coastal) and deletions (coastal->0)\n    while (timer.elapsed() < TL) {\n        bool doDel = true;\n        if (!recCand.empty() && (delCand.empty() || (rng() % 100) >= 70)) doDel = false;\n\n        if (doDel) {\n            if (delCand.empty()) continue;\n            int r = (int)(rng() % delCand.size());\n            int id = delCand[r];\n            delCand[r] = delCand.back();\n            delCand.pop_back();\n\n            int i = id / n, j = id % n;\n            int c = g[i][j];\n            if (c == 0) continue;\n            if (!coastal(c)) continue;\n            if (!adjacent_to_zero_or_outside(i, j)) continue;\n\n            if (try_apply(i, j, 0)) {\n                push_around(i, j);\n            }\n        } else {\n            int r = (int)(rng() % recCand.size());\n            int id = recCand[r];\n            recCand[r] = recCand.back();\n            recCand.pop_back();\n\n            int i = id / n, j = id % n;\n            int a = g[i][j];\n            if (!inland(a)) continue;\n\n            // Choose a neighboring coastal color to absorb this inland cell\n            int opts[4];\n            int osz = 0;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (!inside(ni, nj)) continue;\n                int b = g[ni][nj];\n                if (b > 0 && coastal(b) && b != a) opts[osz++] = b;\n            }\n            if (osz == 0) continue;\n            int b = opts[rng() % osz];\n\n            int dI = delta_interface(i, j, a, b);\n            // Strong bias: only accept if it does not increase inland\u2013coastal boundary\n            if (dI > 0) continue;\n            if (dI == 0 && (rng() % 10) != 0) continue; // small exploration\n\n            if (try_apply(i, j, b)) {\n                push_around(i, j);\n            }\n        }\n    }\n\n    // Final greedy deletion pass (as much as time allows)\n    while (timer.elapsed() < TL && !delCand.empty()) {\n        int r = (int)(rng() % delCand.size());\n        int id = delCand[r];\n        delCand[r] = delCand.back();\n        delCand.pop_back();\n\n        int i = id / n, j = id % n;\n        int c = g[i][j];\n        if (c == 0) continue;\n        if (!coastal(c)) continue;\n        if (!adjacent_to_zero_or_outside(i, j)) continue;\n\n        if (try_apply(i, j, 0)) push_around(i, j);\n    }\n\n    // Final verification (safety). If fail, output original.\n    auto verify = [&]() -> bool {\n        // each color exists\n        vector<int> cnt(C, 0);\n        for (int i = 0; i < n; i++)\n            for (int j = 0; j < n; j++)\n                cnt[g[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cnt[c] == 0) return false;\n\n        // connectivity for each color 1..m\n        vector<int> v(n * n, 0);\n        int st = 1;\n        for (int c = 1; c <= m; c++) {\n            int si = -1, sj = -1;\n            for (int i = 0; i < n && si == -1; i++)\n                for (int j = 0; j < n; j++)\n                    if (g[i][j] == c) { si = i; sj = j; break; }\n            st++;\n            deque<pair<int,int>> q;\n            q.push_back({si, sj});\n            v[idx(si, sj)] = st;\n            int got = 1;\n            while (!q.empty()) {\n                auto [x, y] = q.front(); q.pop_front();\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + DX[k], ny = y + DY[k];\n                    if (!inside(nx, ny)) continue;\n                    if (g[nx][ny] != c) continue;\n                    int id = idx(nx, ny);\n                    if (v[id] == st) continue;\n                    v[id] = st;\n                    q.push_back({nx, ny});\n                    got++;\n                }\n            }\n            if (got != cnt[c]) return false;\n        }\n\n        // 0 connected to outside (check in padded grid)\n        int N = n + 2;\n        auto at = [&](int x, int y) -> int {\n            if (x == 0 || y == 0 || x == N - 1 || y == N - 1) return 0;\n            return g[x - 1][y - 1];\n        };\n        vector<char> vz(N * N, 0);\n        deque<pair<int,int>> q0;\n        q0.push_back({0, 0});\n        vz[0] = 1;\n        while (!q0.empty()) {\n            auto [x, y] = q0.front(); q0.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < N && 0 <= ny && ny < N)) continue;\n                int nid = nx * N + ny;\n                if (vz[nid]) continue;\n                if (at(nx, ny) != 0) continue;\n                vz[nid] = 1;\n                q0.push_back({nx, ny});\n            }\n        }\n        for (int x = 1; x <= n; x++)\n            for (int y = 1; y <= n; y++)\n                if (g[x - 1][y - 1] == 0 && !vz[x * N + y]) return false;\n\n        // adjacency graph equals req\n        vector<vector<char>> outAdj(C, vector<char>(C, 0));\n        auto mark = [&](int u, int v) {\n            if (u == v) return;\n            outAdj[u][v] = outAdj[v][u] = 1;\n        };\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int a = g[i][j];\n                if (i + 1 < n) mark(a, g[i + 1][j]);\n                if (j + 1 < n) mark(a, g[i][j + 1]);\n                if (i == 0) mark(0, a);\n                if (i == n - 1) mark(0, a);\n                if (j == 0) mark(0, a);\n                if (j == n - 1) mark(0, a);\n            }\n        }\n        for (int u = 0; u <= m; u++)\n            for (int v = u + 1; v <= m; v++)\n                if (outAdj[u][v] != req[u][v]) return false;\n\n        return true;\n    };\n\n    if (!verify()) g = orig;\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (j) cout << ' ';\n            cout << g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    using ull = unsigned long long;\n    ull x;\n    explicit XorShift(ull seed = 88172645463325252ULL) : x(seed) {}\n    ull nextUll() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextUll() % (ull)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<vector<int>> bins;\n    vector<int> ans;\n\n    // cache for singleton comparisons: cmp(i,j) in {-1,0,1} meaning wi ? wj\n    // store only for i<j\n    vector<vector<int8_t>> itemCmp; // 2D NxN, 2: unknown, else -1/0/1\n\n    XorShift rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    char querySets(const vector<int>& L, const vector<int>& R) {\n        // Must not exceed Q in communication.\n        // Caller must ensure used < Q and L,R non-empty disjoint.\n        cout << (int)L.size() << \" \" << (int)R.size();\n        for (int x : L) cout << \" \" << x;\n        for (int x : R) cout << \" \" << x;\n        cout << \"\\n\";\n        cout.flush();\n\n        string s;\n        cin >> s;\n        used++;\n        return s[0];\n    }\n\n    int cmpItemNoCache(int i, int j) {\n        // return -1 if wi<wj, 0 if =, +1 if wi>wj\n        vector<int> L = {i}, R = {j};\n        char r = querySets(L, R);\n        if (r == '<') return -1;\n        if (r == '>') return +1;\n        return 0;\n    }\n\n    int cmpItem(int i, int j) {\n        if (i == j) return 0;\n        int a = min(i, j), b = max(i, j);\n        int8_t &v = itemCmp[a][b];\n        if (v != 2) {\n            int res = (int)v;\n            if (i == a) return res;\n            return -res;\n        }\n        int res = cmpItemNoCache(i, j);\n        // store as (a ? b)\n        int store = (i == a ? res : -res);\n        itemCmp[a][b] = (int8_t)store;\n        return res;\n    }\n\n    // Compare two bin sums: return -1 if binA < binB, 0 if =, +1 if >\n    int cmpBins(int a, int b) {\n        char r = querySets(bins[a], bins[b]);\n        if (r == '<') return -1;\n        if (r == '>') return +1;\n        return 0;\n    }\n\n    int findLightestBin() {\n        int best = 0;\n        for (int i = 1; i < D; i++) {\n            if (used >= Q) break;\n            int c = cmpBins(best, i);\n            if (c == +1) best = i; // best heavier -> i is lighter\n        }\n        return best;\n    }\n\n    int findHeaviestBin() {\n        int best = 0;\n        for (int i = 1; i < D; i++) {\n            if (used >= Q) break;\n            int c = cmpBins(best, i);\n            if (c == -1) best = i; // best lighter -> i is heavier\n        }\n        return best;\n    }\n\n    vector<int> pickKDistinctBins(int k) {\n        vector<int> pool(D);\n        iota(pool.begin(), pool.end(), 0);\n        for (int i = 0; i < k; i++) {\n            int j = rng.nextInt(i, D - 1);\n            swap(pool[i], pool[j]);\n        }\n        pool.resize(k);\n        return pool;\n    }\n\n    int tournamentLightest(const vector<int>& cand) {\n        int best = cand[0];\n        for (int idx = 1; idx < (int)cand.size(); idx++) {\n            if (used >= Q) break;\n            int b = cand[idx];\n            int c = cmpBins(best, b);\n            if (c == +1) best = b;\n        }\n        return best;\n    }\n\n    void moveItemBetweenBins(int item, int from, int to) {\n        // remove from \"from\"\n        auto &vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); i++) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        ans[item] = to;\n    }\n\n    vector<int> buildOrderByPivots(int P, const vector<int>& items) {\n        // Choose first P as pivots (items already shuffled).\n        vector<int> piv(items.begin(), items.begin() + P);\n\n        // Insertion sort pivots ascending by weight\n        for (int i = 1; i < P; i++) {\n            int x = piv[i];\n            int j = i - 1;\n            while (j >= 0) {\n                if (used >= Q) break;\n                int c = cmpItem(piv[j], x); // piv[j] ? x\n                if (c <= 0) break; // piv[j] <= x\n                piv[j + 1] = piv[j];\n                j--;\n            }\n            piv[j + 1] = x;\n        }\n\n        vector<vector<int>> bucket(P + 1);\n        vector<char> isPivot(N, 0);\n        for (int x : piv) isPivot[x] = 1;\n\n        // Classify others by upper_bound among pivots (ascending):\n        // bucket idx in [0..P], where 0: <piv0, P: >= piv[P-1]\n        for (int x : items) {\n            if (isPivot[x]) continue;\n            int lo = 0, hi = P;\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                if (used >= Q) break;\n                int c = cmpItem(x, piv[mid]); // x ? piv[mid]\n                if (c < 0) hi = mid;\n                else lo = mid + 1;\n            }\n            bucket[lo].push_back(x);\n        }\n\n        // Build heavy -> light order:\n        vector<int> order;\n        order.reserve(N);\n\n        // bucket[P] (>= heaviest pivot), then piv[P-1], then bucket[P-1], ...\n        for (int j = P; j >= 1; j--) {\n            auto &b = bucket[j];\n            // shuffle within bucket for diversity\n            for (int t = (int)b.size() - 1; t > 0; t--) {\n                int u = rng.nextInt(0, t);\n                swap(b[t], b[u]);\n            }\n            for (int x : b) order.push_back(x);\n            order.push_back(piv[j - 1]);\n        }\n        // finally lightest bucket[0]\n        {\n            auto &b = bucket[0];\n            for (int t = (int)b.size() - 1; t > 0; t--) {\n                int u = rng.nextInt(0, t);\n                swap(b[t], b[u]);\n            }\n            for (int x : b) order.push_back(x);\n        }\n\n        // In rare case used>=Q breaks binary searches early; still must be a permutation.\n        // Ensure all items included once.\n        vector<char> seen(N, 0);\n        vector<int> fixed;\n        fixed.reserve(N);\n        for (int x : order) {\n            if (!seen[x]) {\n                seen[x] = 1;\n                fixed.push_back(x);\n            }\n        }\n        for (int x : items) if (!seen[x]) fixed.push_back(x);\n        return fixed;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        ans.assign(N, 0);\n        bins.assign(D, {});\n        itemCmp.assign(N, vector<int8_t>(N, 2));\n\n        // deterministic seed based on input (contest-friendly)\n        unsigned long long seed = 1234567ULL;\n        seed ^= (unsigned long long)N * 1000003ULL;\n        seed ^= (unsigned long long)D * 10007ULL;\n        seed ^= (unsigned long long)Q * 97ULL;\n        rng = XorShift(seed);\n\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        // shuffle items\n        for (int i = N - 1; i > 0; i--) {\n            int j = rng.nextInt(0, i);\n            swap(items[i], items[j]);\n        }\n\n        // Decide pivot count P (2/4/8) under a simple budget constraint.\n        auto costForP = [&](int P) -> int {\n            if (P <= 1) return 0;\n            int pivSort = P * (P - 1) / 2;\n            int lg = 0;\n            while ((1 << lg) < P) lg++;\n            // upper_bound uses lg comparisons worst-case\n            int classify = (N - P) * lg;\n            return pivSort + classify;\n        };\n\n        int minAssign = max(0, N - D); // keep at least 1 comparison per item possible (k=2) if desired\n        int P = 2;\n        for (int cand : {8, 4, 2}) {\n            if (cand <= N && costForP(cand) <= max(0, Q - minAssign)) {\n                P = cand;\n                break;\n            }\n        }\n\n        vector<int> order = buildOrderByPivots(P, items);\n\n        // --- Initial seeding: 1 item per bin (no queries) ---\n        for (int b = 0; b < D; b++) {\n            int it = order[b];\n            bins[b].push_back(it);\n            ans[it] = b;\n        }\n\n        // --- Greedy assignment with adaptive k-choice ---\n        for (int t = D; t < N; t++) {\n            int it = order[t];\n\n            int remainingItems = N - t;\n            int remainingQueries = Q - used;\n            if (remainingItems <= 0) break;\n\n            // keep ~30% of remaining queries for improvement phase\n            long long budgetAssign = (long long)remainingQueries * 7 / 10;\n            int compsPerItem = 0;\n            if (remainingItems > 0) compsPerItem = (int)(budgetAssign / remainingItems);\n\n            // k candidates => (k-1) comparisons\n            int k = min(D, compsPerItem + 1);\n            k = max(k, 2);\n            if (remainingQueries <= 0) {\n                // no queries left, random placement\n                int b = rng.nextInt(0, D - 1);\n                bins[b].push_back(it);\n                ans[it] = b;\n                continue;\n            }\n            if (k - 1 > remainingQueries) k = remainingQueries + 1;\n            if (k < 2) k = 2;\n\n            vector<int> cand = pickKDistinctBins(k);\n            int best = tournamentLightest(cand);\n\n            bins[best].push_back(it);\n            ans[it] = best;\n\n            if (used >= Q) break;\n        }\n\n        // --- Local improvement: move from heaviest to lightest ---\n        while (used < Q) {\n            // Need at least (D-1)+(D-1)+1 queries to do something meaningful\n            if (Q - used < 2 * (D - 1) + 1) break;\n\n            int L = findLightestBin();\n            if (used >= Q) break;\n            int H = findHeaviestBin();\n            if (used >= Q) break;\n\n            if (L == H) break;\n            // If already equal, stop\n            {\n                int c = cmpBins(H, L);\n                if (used >= Q) break;\n                if (c == 0) break;\n                // if somehow H is not heavier due to ties/noise, skip\n                if (c < 0) continue;\n            }\n\n            if ((int)bins[H].size() <= 1) break; // keep bins non-empty for further queries\n\n            // Try moving one item x from H to L.\n            // Evaluate each candidate by comparing (H\\{x}) vs (L U {x}).\n            int bestEq = -1;\n            int bestOvershoot = -1;  // makes newH < newL (overshoot)\n            int bestStillHeavy = -1; // keeps newH > newL\n\n            auto lighterItem = [&](int a, int b) -> int {\n                // return the lighter one (by singleton cmp)\n                if (a == -1) return b;\n                if (b == -1) return a;\n                if (used >= Q) return a;\n                int c = cmpItem(a, b); // a ? b\n                if (c <= 0) return a;\n                return b;\n            };\n            auto heavierItem = [&](int a, int b) -> int {\n                // return the heavier one\n                if (a == -1) return b;\n                if (b == -1) return a;\n                if (used >= Q) return a;\n                int c = cmpItem(a, b);\n                if (c >= 0) return a;\n                return b;\n            };\n\n            // Pre-copy L set once\n            vector<int> setL = bins[L];\n\n            // We'll test all candidates except leaving at least one in H.\n            for (int idx = 0; idx < (int)bins[H].size(); idx++) {\n                if (used >= Q) break;\n                if ((int)bins[H].size() <= 1) break;\n\n                int x = bins[H][idx];\n\n                // Build setA = H without x\n                vector<int> setA;\n                setA.reserve(bins[H].size() - 1);\n                for (int y : bins[H]) if (y != x) setA.push_back(y);\n                if (setA.empty()) continue; // keep non-empty for query\n\n                // Build setB = L with x\n                vector<int> setB = setL;\n                setB.push_back(x);\n\n                char r = querySets(setA, setB); // compares newH vs newL\n                if (r == '=') {\n                    bestEq = x;\n                    break;\n                } else if (r == '<') {\n                    // overshoot: newH < newL, want smallest x among overshoots\n                    bestOvershoot = lighterItem(bestOvershoot, x);\n                } else { // '>'\n                    // still heavy: want largest x to reduce more\n                    bestStillHeavy = heavierItem(bestStillHeavy, x);\n                }\n\n                // if queries running low, stop early\n                if (Q - used < 2) break;\n            }\n\n            int chosen = -1;\n            if (bestEq != -1) chosen = bestEq;\n            else if (bestOvershoot != -1) chosen = bestOvershoot;\n            else chosen = bestStillHeavy;\n\n            if (chosen == -1) break;\n\n            // Apply move (ensure H keeps >=1 item)\n            if ((int)bins[H].size() <= 1) break;\n            moveItemBetweenBins(chosen, H, L);\n        }\n\n        // --- Dummy queries to reach exactly Q ---\n        // Compare {0} vs {1} repeatedly (valid because disjoint and non-empty).\n        while (used < Q) {\n            vector<int> L = {0}, R = {1};\n            (void)querySets(L, R);\n        }\n\n        // --- Output final assignment ---\n        for (int i = 0; i < N; i++) {\n            if (i) cout << \" \";\n            cout << ans[i];\n        }\n        cout << \"\\n\";\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 200;\nstatic constexpr int M = 10;\nstatic constexpr int INF = INT_MAX;\n\nstruct Weights {\n    // Base shape (similar spirit to previous, but tuned to work with new \"badMin\" term)\n    double wHeight = 0.06;\n    double wMinUrg = 230.0;\n    double wTopUrg = 85.0;\n    double wMinAtTopExtra = 260.0;\n\n    double badTopBase = 4200.0;\n    double badTopSlope = 8.0;\n\n    // New: penalize burying a stack's minimum that is <= pileMax (risk of future deadlock/moves)\n    double badMinBase = 2600.0;\n    double badMinSlope = 90.0;\n\n    // Slightly discourage consuming empty stack when other safe choices exist\n    double emptyReserve = 35.0;\n\n    int candK = 5;      // candidates evaluated with lookahead\n    int lookahead = 12; // number of \"removals\" simulated in lookahead\n};\n\nstruct Result {\n    long long energy = (1LL<<60);\n    vector<pair<int,int>> ops;\n};\n\nstatic inline uint64_t xorshift64(uint64_t &x) {\n    x ^= x << 7;\n    x ^= x >> 9;\n    return x;\n}\n\nstruct State {\n    array<array<int, N>, M> a{};\n    array<int, M> sz{};\n    array<int, N + 1> posS{};\n    array<int, N + 1> posI{};\n\n    array<int, M> top{};\n    array<int, M> mn{};\n    array<int, M> posMinFromTop{};\n\n    void recalc(int i) {\n        int h = sz[i];\n        if (h == 0) {\n            top[i] = INF;\n            mn[i] = INF;\n            posMinFromTop[i] = 0;\n            return;\n        }\n        top[i] = a[i][h - 1];\n        int best = INF, bestIdx = 0;\n        for (int j = 0; j < h; j++) {\n            int v = a[i][j];\n            if (v < best) {\n                best = v;\n                bestIdx = j;\n            }\n        }\n        mn[i] = best;\n        posMinFromTop[i] = (h - 1) - bestIdx;\n    }\n\n    void initFromInput(const vector<vector<int>> &init) {\n        for (int i = 0; i < M; i++) {\n            sz[i] = (int)init[i].size();\n            for (int j = 0; j < sz[i]; j++) {\n                a[i][j] = init[i][j];\n                posS[a[i][j]] = i;\n                posI[a[i][j]] = j;\n            }\n        }\n        for (int v = 1; v <= N; v++) {\n            // all present\n        }\n        for (int i = 0; i < M; i++) recalc(i);\n    }\n\n    inline bool isOnTop(int v) const {\n        int s = posS[v];\n        int idx = posI[v];\n        return (s >= 0 && idx == sz[s] - 1);\n    }\n\n    inline void popTop(int s) {\n        int v = a[s][sz[s] - 1];\n        sz[s]--;\n        posS[v] = -1;\n        posI[v] = -1;\n        recalc(s);\n    }\n\n    inline void moveSuffix(int s, int start, int d) {\n        // move a[s][start..sz[s]) to a[d][sz[d]..)\n        int k = sz[s] - start;\n        int base = sz[d];\n        for (int i = 0; i < k; i++) {\n            int x = a[s][start + i];\n            a[d][base + i] = x;\n            posS[x] = d;\n            posI[x] = base + i;\n        }\n        sz[d] += k;\n        sz[s] = start;\n        recalc(s);\n        recalc(d);\n    }\n\n    inline pair<int,int> locate(int v) const {\n        return {posS[v], posI[v]};\n    }\n};\n\nstruct Solver {\n    State init;\n\n    explicit Solver(const vector<vector<int>> &st0) {\n        init.initFromInput(st0);\n    }\n\n    static inline double destPenalty(\n        const State &st,\n        int t,\n        int s,\n        int d,\n        int k,\n        int pileMax,\n        const Weights &w\n    ) {\n        if (d == s) return 1e100;\n\n        int h = st.sz[d];\n        if (h == 0) {\n            // empty is very safe, but keep a small \"reserve\" penalty to avoid consuming it too eagerly\n            return w.emptyReserve + w.wHeight * double(k);\n        }\n\n        int top = st.top[d];\n        int mn = st.mn[d];\n        int posMin = st.posMinFromTop[d];\n\n        // since t is global minimum remaining, mn and top should be > t in other stacks\n        double deltaMin = double(mn - t);\n        double deltaTop = double(top - t);\n        if (deltaMin < 1.0) deltaMin = 1.0;\n        if (deltaTop < 1.0) deltaTop = 1.0;\n\n        double p = 0.0;\n        p += w.wHeight * double(h + k);\n        p += w.wMinUrg * double(k) / (deltaMin + 1.0);\n        p += w.wTopUrg * double(k) / (deltaTop + 1.0);\n\n        if (posMin == 0) {\n            p += w.wMinAtTopExtra * double(k + 1) / (deltaMin + 1.0);\n        }\n\n        // If destination top is smaller than something in pile, very risky\n        if (top < pileMax) {\n            p += w.badTopBase + w.badTopSlope * double(pileMax - top + 1);\n        }\n\n        // New: if destination minimum is <= pileMax, then when that minimum becomes needed,\n        // pile may still contain larger-than-min items, forcing extra relocations.\n        if (mn < pileMax) {\n            p += w.badMinBase + w.badMinSlope * double(pileMax - mn + 1) / (deltaMin + 1.0);\n        }\n\n        return p;\n    }\n\n    static int chooseDestBase(const State &st, int t, int s, int k, int pileMax, const Weights &w) {\n        // Prefer a \"safe\" stack where mn > pileMax (empty counts with mn=INF, used last automatically)\n        int bestSafe = -1;\n        int bestSafeMn = INF;\n        int bestSafeH = INF;\n        for (int d = 0; d < M; d++) if (d != s) {\n            int mn = st.mn[d];\n            if (mn > pileMax) {\n                int h = st.sz[d];\n                if (mn < bestSafeMn || (mn == bestSafeMn && h < bestSafeH)) {\n                    bestSafeMn = mn;\n                    bestSafeH = h;\n                    bestSafe = d;\n                }\n            }\n        }\n        if (bestSafe != -1) return bestSafe;\n\n        // Otherwise minimize penalty\n        double bestP = 1e100;\n        int bestD = (s + 1) % M;\n        for (int d = 0; d < M; d++) if (d != s) {\n            double p = destPenalty(st, t, s, d, k, pileMax, w);\n            if (p < bestP) {\n                bestP = p;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\n    static long long simulateEnergy(State st, int tStart, int maxRemovals, const Weights &w) {\n        long long e = 0;\n        int t = tStart;\n        int removed = 0;\n\n        while (t <= N && removed < maxRemovals) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                st.popTop(s);\n                t++;\n                removed++;\n            } else {\n                int start = idx + 1;\n                int k = st.sz[s] - start;\n                int pileMax = 0;\n                for (int i = start; i < st.sz[s]; i++) pileMax = max(pileMax, st.a[s][i]);\n\n                int d = chooseDestBase(st, t, s, k, pileMax, w);\n                st.moveSuffix(s, start, d);\n                e += (long long)k + 1;\n            }\n        }\n        return e;\n    }\n\n    static int chooseDestWithLookahead(State const &st, int t, int s, int start, int k, int pileMax,\n                                      const Weights &w, uint64_t &rng) {\n        // Rank by heuristic penalty and evaluate top candK by simulation\n        vector<pair<double,int>> ranked;\n        ranked.reserve(M - 1);\n        for (int d = 0; d < M; d++) if (d != s) {\n            double p = destPenalty(st, t, s, d, k, pileMax, w);\n            // tiny noise to break ties across trials\n            p += double(int(xorshift64(rng) % 1000)) * 1e-9;\n            ranked.push_back({p, d});\n        }\n        sort(ranked.begin(), ranked.end());\n\n        int K = min(w.candK, (int)ranked.size());\n\n        long long bestScore = (1LL<<62);\n        int bestD = ranked[0].second;\n\n        for (int i = 0; i < K; i++) {\n            int d = ranked[i].second;\n            State st2 = st;\n            st2.moveSuffix(s, start, d);\n            long long score = (long long)k + 1;\n            score += simulateEnergy(st2, t, w.lookahead, w);\n            if (score < bestScore) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\n    Result run(const Weights &w, uint64_t seed) {\n        uint64_t rng = seed;\n        State st = init;\n        vector<pair<int,int>> ops;\n        ops.reserve(1500);\n\n        long long energy = 0;\n        int t = 1;\n\n        while (t <= N) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break; // should not happen\n\n            if (idx == st.sz[s] - 1) {\n                ops.push_back({t, 0});\n                st.popTop(s);\n                t++;\n            } else {\n                int start = idx + 1;\n                int k = st.sz[s] - start;\n                int v = st.a[s][start];\n\n                int pileMax = 0;\n                for (int i = start; i < st.sz[s]; i++) pileMax = max(pileMax, st.a[s][i]);\n\n                int d = chooseDestWithLookahead(st, t, s, start, k, pileMax, w, rng);\n\n                ops.push_back({v, d + 1});\n                st.moveSuffix(s, start, d);\n                energy += (long long)k + 1;\n            }\n\n            if ((int)ops.size() > 5000) break; // safety\n        }\n\n        return Result{energy, std::move(ops)};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> initStacks(M);\n    for (int i = 0; i < M; i++) {\n        initStacks[i].resize(n / m);\n        for (int j = 0; j < n / m; j++) cin >> initStacks[i][j];\n    }\n\n    Solver solver(initStacks);\n\n    Weights base;\n\n    auto t0 = chrono::high_resolution_clock::now();\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result best;\n    best.energy = (1LL<<60);\n\n    int trials = 0;\n    while (true) {\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - t0).count();\n        if (elapsed > 1.93) break;\n\n        Weights w = base;\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)trials;\n        uint64_t rng = seed;\n\n        auto rand01 = [&]() -> double {\n            return (double)(xorshift64(rng) % 1000000) / 1000000.0;\n        };\n        auto mult = [&](double x, double lo, double hi) {\n            return x * (lo + (hi - lo) * rand01());\n        };\n\n        if (trials > 0) {\n            w.wHeight = mult(w.wHeight, 0.7, 1.4);\n            w.wMinUrg = mult(w.wMinUrg, 0.75, 1.35);\n            w.wTopUrg = mult(w.wTopUrg, 0.75, 1.35);\n            w.wMinAtTopExtra = mult(w.wMinAtTopExtra, 0.75, 1.45);\n\n            w.badTopBase = mult(w.badTopBase, 0.7, 1.4);\n            w.badTopSlope = mult(w.badTopSlope, 0.7, 1.6);\n\n            w.badMinBase = mult(w.badMinBase, 0.7, 1.5);\n            w.badMinSlope = mult(w.badMinSlope, 0.7, 1.6);\n\n            w.emptyReserve = mult(w.emptyReserve, 0.6, 1.6);\n\n            // sometimes deeper/shallower lookahead\n            double r = rand01();\n            if (r < 0.20) w.lookahead = 10;\n            else if (r < 0.45) w.lookahead = 14;\n            else w.lookahead = 12;\n\n            // candidate count tweaks\n            double r2 = rand01();\n            if (r2 < 0.25) w.candK = 4;\n            else if (r2 < 0.55) w.candK = 5;\n            else w.candK = 6;\n        }\n\n        Result cur = solver.run(w, seed);\n        if ((int)cur.ops.size() <= 5000 && cur.energy < best.energy) {\n            best = std::move(cur);\n        }\n\n        trials++;\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << \" \" << i << \"\\n\";\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline char oppositeDir(char c) {\n    if (c == 'U') return 'D';\n    if (c == 'D') return 'U';\n    if (c == 'L') return 'R';\n    return 'L';\n}\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\nstatic const char DIRCH[4] = {'U','D','L','R'};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed=0) { if(seed) x = seed; }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(next() % (uint64_t)(hi - lo + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct AnalysisResult {\n    bool ok = false;\n    long long sumSq = (1LL<<62);\n    long double metric = 1e100L;\n\n    vector<int> pos;          // pos[k] vertex before move k, size L+1, pos[0]=0\n    vector<int> first, last;\n    vector<int> bestGapLen;   // per vertex\n    vector<int> bestGapStart; // start time (arrival index) of previous visit for best gap\n};\n\nstruct Solver {\n    int N, V;\n    vector<string> h, v;\n    vector<int> d;                    // size V\n    vector<array<int,4>> nxt;         // adjacency (U,D,L,R), -1 if wall\n\n    vector<int> bfsDist, bfsPrev;\n    vector<char> bfsPrevMove;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    int id(int i, int j) const { return i*N + j; }\n\n    void readInput() {\n        cin >> N;\n        V = N*N;\n        h.resize(N-1);\n        v.resize(N);\n        for (int i=0;i<N-1;i++) cin >> h[i];\n        for (int i=0;i<N;i++) cin >> v[i];\n        d.assign(V, 0);\n        for (int i=0;i<N;i++) for (int j=0;j<N;j++) {\n            int x; cin >> x;\n            d[id(i,j)] = x;\n        }\n\n        nxt.assign(V, array<int,4>{-1,-1,-1,-1});\n        for (int i=0;i<N;i++) for (int j=0;j<N;j++) {\n            int u = id(i,j);\n            if (i > 0   && h[i-1][j] == '0') nxt[u][0] = id(i-1,j);\n            if (i < N-1 && h[i][j]   == '0') nxt[u][1] = id(i+1,j);\n            if (j > 0   && v[i][j-1] == '0') nxt[u][2] = id(i,j-1);\n            if (j < N-1 && v[i][j]   == '0') nxt[u][3] = id(i,j+1);\n        }\n\n        bfsDist.assign(V, -1);\n        bfsPrev.assign(V, -1);\n        bfsPrevMove.assign(V, 0);\n    }\n\n    // BFS distances only\n    void bfsDistances(int src, vector<int>& dist) {\n        dist.assign(V, -1);\n        deque<int> q;\n        dist[src] = 0;\n        q.push_back(src);\n        while(!q.empty()) {\n            int u = q.front(); q.pop_front();\n            int du = dist[u];\n            for(int k=0;k<4;k++){\n                int w = nxt[u][k];\n                if(w < 0 || dist[w] != -1) continue;\n                dist[w] = du + 1;\n                q.push_back(w);\n            }\n        }\n    }\n\n    // BFS shortest path moves from s to t\n    string shortestPathMoves(int s, int t) {\n        if (s == t) return {};\n        fill(bfsDist.begin(), bfsDist.end(), -1);\n        deque<int> q;\n        bfsDist[s] = 0;\n        bfsPrev[s] = -1;\n        q.push_back(s);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            int du=bfsDist[u];\n            for(int k=0;k<4;k++){\n                int w=nxt[u][k];\n                if(w<0||bfsDist[w]!=-1) continue;\n                bfsDist[w]=du+1;\n                bfsPrev[w]=u;\n                bfsPrevMove[w]=DIRCH[k];\n                if(w==t) { q.clear(); break; }\n                q.push_back(w);\n            }\n        }\n        if (bfsDist[t] == -1) return {};\n        string path;\n        int cur = t;\n        while(cur != s){\n            char mv = bfsPrevMove[cur];\n            path.push_back(mv);\n            cur = bfsPrev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Randomized greedy spanning tree\n    void buildSpanningTree(vector<int>& parent, vector<char>& parentDir, vector<int>& order,\n                          XorShift& rng, int gamma, int noiseScale) {\n        parent.assign(V, -1);\n        parentDir.assign(V, '?');\n        vector<int> depth(V, 0);\n        vector<char> vis(V, 0);\n        order.clear();\n        order.reserve(V);\n\n        struct Cand { int key; int p; int x; char dir; };\n        struct Cmp { bool operator()(const Cand& a, const Cand& b) const { return a.key < b.key; } };\n        priority_queue<Cand, vector<Cand>, Cmp> pq;\n\n        auto pushNeighbors = [&](int u){\n            for(int k=0;k<4;k++){\n                int w = nxt[u][k];\n                if(w < 0 || vis[w]) continue;\n                int candDepth = depth[u] + 1;\n                int noise = (noiseScale ? rng.nextInt(0, noiseScale) : 0);\n                // scale to keep key integer and stable\n                int key = d[w]*1024 - gamma*candDepth*1024 + noise;\n                pq.push(Cand{key, u, w, DIRCH[k]});\n            }\n        };\n\n        const int ROOT = 0;\n        vis[ROOT] = 1;\n        order.push_back(ROOT);\n        pushNeighbors(ROOT);\n\n        while((int)order.size() < V){\n            if(pq.empty()) break;\n            auto c = pq.top(); pq.pop();\n            if(vis[c.x]) continue;\n            vis[c.x] = 1;\n            parent[c.x] = c.p;\n            parentDir[c.x] = c.dir;\n            depth[c.x] = depth[c.p] + 1;\n            order.push_back(c.x);\n            pushNeighbors(c.x);\n        }\n\n        // fallback BFS if something odd\n        if((int)order.size() < V){\n            parent.assign(V, -1);\n            parentDir.assign(V, '?');\n            order.clear();\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1;\n            q.push_back(0);\n            order.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent[w]=u;\n                    parentDir[w]=DIRCH[k];\n                    q.push_back(w);\n                    order.push_back(w);\n                }\n            }\n        }\n    }\n\n    string buildEulerRoute(const vector<int>& parent, const vector<char>& parentDir, const vector<int>& order,\n                           XorShift& rng, int childNoise) {\n        vector<vector<int>> children(V);\n        for(int x=1;x<V;x++){\n            int p=parent[x];\n            if(p>=0) children[p].push_back(x);\n        }\n        vector<long long> sub(V);\n        for(int i=0;i<V;i++) sub[i]=d[i];\n        for(int idx=(int)order.size()-1; idx>=1; --idx){\n            int x=order[idx];\n            int p=parent[x];\n            if(p>=0) sub[p] += sub[x];\n        }\n        for(int u=0;u<V;u++){\n            auto &ch = children[u];\n            sort(ch.begin(), ch.end(), [&](int a, int b){\n                long long ka = sub[a]*1024 + d[a]*8 + (childNoise? (int)(rng.next()%childNoise) : 0);\n                long long kb = sub[b]*1024 + d[b]*8 + (childNoise? (int)(rng.next()%childNoise) : 0);\n                if(ka!=kb) return ka>kb;\n                return a<b;\n            });\n        }\n\n        string route;\n        route.reserve(2*(V-1)+10);\n        function<void(int)> dfs = [&](int u){\n            for(int x: children[u]){\n                route.push_back(parentDir[x]);\n                dfs(x);\n                route.push_back(oppositeDir(parentDir[x]));\n            }\n        };\n        dfs(0);\n        return route;\n    }\n\n    AnalysisResult analyzeRoute(const string& route) {\n        AnalysisResult res;\n        int L = (int)route.size();\n        if(L<=0) return res;\n\n        res.pos.assign(L+1, 0);\n        res.first.assign(V, -1);\n        res.last.assign(V, -1);\n        res.bestGapLen.assign(V, -1);\n        res.bestGapStart.assign(V, 0);\n\n        long long sumSq = 0;\n        int cur = 0;\n        res.pos[0] = 0;\n\n        for(int i=0;i<L;i++){\n            int k = dirId(route[i]);\n            int nx = nxt[cur][k];\n            if(nx < 0) return res; // illegal\n            cur = nx;\n            res.pos[i+1] = cur;\n            int t = i;\n            int vtx = cur;\n            if(res.first[vtx] == -1){\n                res.first[vtx] = res.last[vtx] = t;\n            }else{\n                int gap = t - res.last[vtx];\n                sumSq += 1LL * d[vtx] * gap * gap;\n                if(gap > res.bestGapLen[vtx]){\n                    res.bestGapLen[vtx] = gap;\n                    res.bestGapStart[vtx] = res.last[vtx];\n                }\n                res.last[vtx] = t;\n            }\n        }\n        if(cur != 0) return res; // must return\n\n        for(int vtx=0; vtx<V; vtx++){\n            if(res.first[vtx] == -1) return res; // unvisited\n            int gap = (res.first[vtx] + L) - res.last[vtx];\n            sumSq += 1LL * d[vtx] * gap * gap;\n            if(gap > res.bestGapLen[vtx]){\n                res.bestGapLen[vtx] = gap;\n                res.bestGapStart[vtx] = res.last[vtx];\n            }\n        }\n\n        res.sumSq = sumSq;\n        res.metric = (long double)sumSq / (long double)L;\n        res.ok = true;\n        return res;\n    }\n\n    long double computeMetric(const string& route, vector<int>& first, vector<int>& last) {\n        int L = (int)route.size();\n        if(L<=0) return 1e100L;\n        fill(first.begin(), first.end(), -1);\n        fill(last.begin(), last.end(), -1);\n\n        long long sumSq = 0;\n        int cur=0;\n        for(int i=0;i<L;i++){\n            int k=dirId(route[i]);\n            int nx=nxt[cur][k];\n            if(nx<0) return 1e100L;\n            cur=nx;\n            int t=i;\n            int vtx=cur;\n            if(first[vtx]==-1){\n                first[vtx]=last[vtx]=t;\n            }else{\n                int gap=t-last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                last[vtx]=t;\n            }\n        }\n        if(cur!=0) return 1e100L;\n        for(int vtx=0; vtx<V; vtx++){\n            if(first[vtx]==-1) return 1e100L;\n            int gap=(first[vtx]+L)-last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n        }\n        return (long double)sumSq/(long double)L;\n    }\n\n    // Choose insertion position near midpoint of the largest gap for target, preferring closer route vertex.\n    // Returns insertion position p (0..L-1) and the distance from pos[p] to target.\n    pair<int,int> chooseInsertPos(const AnalysisResult& ar, int target, const vector<int>& distToTarget) {\n        int L = (int)ar.pos.size() - 1;\n        int startT = ar.bestGapStart[target];\n        int len = ar.bestGapLen[target];\n        long long midT = (long long)startT + len/2;\n        int baseP = (int)((midT + 1) % L); // insertion before move baseP\n\n        int W = min(30, max(1, len/4)); // search window\n        int bestP = baseP;\n        int bestDist = INT_MAX;\n        int bestAbs = INT_MAX;\n\n        for(int off=-W; off<=W; off++){\n            int p = baseP + off;\n            p %= L;\n            if(p<0) p += L;\n            int vtx = ar.pos[p];\n            int dist = distToTarget[vtx];\n            if(dist < 0) continue;\n            int aoff = abs(off);\n            if(dist < bestDist || (dist==bestDist && aoff < bestAbs)){\n                bestDist = dist;\n                bestAbs = aoff;\n                bestP = p;\n            }\n        }\n        return {bestP, bestDist};\n    }\n\n    void improveByDetours(string& route, Timer& timer, double endTimeSec) {\n        vector<int> tmpFirst(V, -1), tmpLast(V, -1);\n\n        while(timer.elapsed() < endTimeSec) {\n            AnalysisResult ar = analyzeRoute(route);\n            if(!ar.ok) break;\n            long double curMetric = ar.metric;\n            int L = (int)route.size();\n            if(L >= 100000) break;\n\n            // Build candidate list by estimated benefit / cost.\n            struct Cand {\n                int vtx;\n                long long estBenefit;\n                int insertPos;\n                int dist;\n                long double ratio;\n            };\n\n            vector<pair<long long,int>> key; key.reserve(V);\n            for(int vtx=0; vtx<V; vtx++){\n                int g = ar.bestGapLen[vtx];\n                if(g <= 1) continue;\n                long long k = 1LL * d[vtx] * g * g;\n                key.push_back({k, vtx});\n            }\n            if(key.empty()) break;\n\n            int K = min<int>(60, (int)key.size());\n            nth_element(key.begin(), key.begin()+K, key.end(),\n                        [&](auto& a, auto& b){ return a.first > b.first; });\n            key.resize(K);\n            sort(key.begin(), key.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n            vector<Cand> cands;\n            cands.reserve(K);\n\n            // For each key candidate, compute nearest insertion pos around mid-gap.\n            vector<int> distToTarget;\n            for(int i=0;i<K;i++){\n                if(timer.elapsed() >= endTimeSec) break;\n                int vtx = key[i].second;\n                int g = ar.bestGapLen[vtx];\n                if(g <= 1) continue;\n\n                bfsDistances(vtx, distToTarget);\n                auto [p, dist] = chooseInsertPos(ar, vtx, distToTarget);\n                if(dist <= 0) continue; // already at target at insertion, skip (rare)\n                int addLen = 2*dist;\n                if(L + addLen > 100000) continue;\n\n                // estimated benefit from splitting gap g into a+b\n                int a = g/2;\n                int b = g - a;\n                long long estBenefit = 1LL * d[vtx] * (1LL*g*g - 1LL*a*a - 1LL*b*b); // >=0\n                if(estBenefit <= 0) continue;\n                long double ratio = (long double)estBenefit / (long double)addLen;\n                cands.push_back(Cand{vtx, estBenefit, p, dist, ratio});\n            }\n            if(cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                return a.ratio > b.ratio;\n            });\n\n            int M = min<int>(12, (int)cands.size());\n            long double bestMetric = curMetric;\n            int bestPos = -1;\n            string bestDetour;\n\n            for(int i=0;i<M;i++){\n                if(timer.elapsed() >= endTimeSec) break;\n                const auto& c = cands[i];\n                int p = c.insertPos;\n                int startVtx = ar.pos[p];\n                string go = shortestPathMoves(startVtx, c.vtx);\n                if(go.empty()) continue;\n                string det = go;\n                det.reserve(go.size()*2);\n                for(int k=(int)go.size()-1;k>=0;k--) det.push_back(oppositeDir(go[k]));\n\n                if((int)route.size() + (int)det.size() > 100000) continue;\n\n                route.insert((size_t)p, det);\n                long double met = computeMetric(route, tmpFirst, tmpLast);\n                route.erase((size_t)p, det.size());\n\n                if(met + 1e-18L < bestMetric){\n                    bestMetric = met;\n                    bestPos = p;\n                    bestDetour = std::move(det);\n                }\n            }\n\n            if(bestPos == -1) break; // local optimum\n            route.insert((size_t)bestPos, bestDetour);\n        }\n    }\n\n    void solve() {\n        Timer timer;\n        double TL = 1.95;\n\n        XorShift rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        string bestRoute;\n        long double bestMetric = 1e100L;\n\n        // multi-start\n        int starts = 7;\n        vector<int> parent, order;\n        vector<char> parentDir;\n        vector<int> tmpFirst(V, -1), tmpLast(V, -1);\n\n        for(int s=0; s<starts; s++){\n            if(timer.elapsed() > TL) break;\n\n            int gamma = 10 + (s%4)*5;                 // 10,15,20,25\n            int noiseScale = 4000 + s*2000;           // increasing randomness\n            int childNoise = 1000 + s*700;\n\n            buildSpanningTree(parent, parentDir, order, rng, gamma, noiseScale);\n            string route = buildEulerRoute(parent, parentDir, order, rng, childNoise);\n\n            // allocate remaining time adaptively\n            double now = timer.elapsed();\n            double remain = max(0.0, TL - now);\n            double per = remain / max(1, starts - s);  // rough\n            double endTime = min(TL, now + per * 0.95);\n\n            improveByDetours(route, timer, endTime);\n\n            long double met = computeMetric(route, tmpFirst, tmpLast);\n            if(met < bestMetric){\n                bestMetric = met;\n                bestRoute = std::move(route);\n            }\n        }\n\n        if(bestRoute.empty()){\n            // fallback (shouldn't happen)\n            bestRoute = \"\";\n        }\n        if((int)bestRoute.size() > 100000) bestRoute.resize(100000);\n        cout << bestRoute << \"\\n\";\n    }\n};\n\nint main() {\n    Solver s;\n    s.readInput();\n    s.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    short r, c;\n};\n\nstatic inline int manhattan(const Pos& a, const Pos& b) {\n    return abs((int)a.r - (int)b.r) + abs((int)a.c - (int)b.c);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n    vector<string> t(M);\n    for (int k = 0; k < M; k++) cin >> t[k];\n\n    // Positions of each letter\n    array<vector<Pos>, 26> pos;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            pos[A[i][j] - 'A'].push_back(Pos{(short)i, (short)j});\n        }\n    }\n\n    Pos start{(short)si, (short)sj};\n\n    // Precompute D[c][d] = min Manhattan distance between any occurrence of c and d.\n    const int INF = 1e9;\n    array<array<int, 26>, 26> D;\n    for (int c = 0; c < 26; c++) {\n        for (int d = 0; d < 26; d++) {\n            int best = INF;\n            for (const auto &p : pos[c]) {\n                for (const auto &q : pos[d]) {\n                    best = min(best, manhattan(p, q));\n                }\n            }\n            D[c][d] = best;\n        }\n    }\n\n    // Distance from start to a letter\n    array<int, 26> Dstart;\n    for (int c = 0; c < 26; c++) {\n        int best = INF;\n        for (const auto &p : pos[c]) best = min(best, manhattan(start, p));\n        Dstart[c] = best;\n    }\n\n    auto overlap_len_suffix_prefix = [&](const string& suffix4, const string& w) -> int {\n        int sl = (int)suffix4.size();\n        int maxl = min(4, sl);\n        for (int l = maxl; l >= 1; --l) {\n            bool ok = true;\n            for (int i = 0; i < l; i++) {\n                if (suffix4[sl - l + i] != w[i]) { ok = false; break; }\n            }\n            if (ok) return l;\n        }\n        return 0;\n    };\n\n    auto update_suffix4 = [&](string& suffix4, const string& appended) {\n        for (char ch : appended) {\n            if ((int)suffix4.size() < 4) suffix4.push_back(ch);\n            else {\n                suffix4.erase(suffix4.begin());\n                suffix4.push_back(ch);\n            }\n        }\n    };\n\n    auto build_from_order_with_overlap = [&](const vector<int>& order) -> string {\n        string S = t[order[0]];\n        string suffix4;\n        for (int i = max(0, (int)S.size() - 4); i < (int)S.size(); i++) suffix4.push_back(S[i]);\n        for (int k = 1; k < (int)order.size(); k++) {\n            const string& w = t[order[k]];\n            int l = overlap_len_suffix_prefix(suffix4, w);\n            string add = w.substr(l);\n            S += add;\n            update_suffix4(suffix4, add);\n        }\n        return S;\n    };\n\n    auto approx_add_cost = [&](char curLast, const string& w, int l) -> int {\n        // Approx additional cost to append w with overlap length l.\n        // Uses D[][] + 1 per typed char.\n        int cost = 0;\n        if (l == 0) {\n            cost += D[curLast - 'A'][w[0] - 'A'] + 1;\n            for (int i = 1; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        } else {\n            for (int i = l; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        }\n        return cost;\n    };\n\n    auto approx_start_cost = [&](const string& w) -> int {\n        int cost = Dstart[w[0] - 'A'] + 1;\n        for (int i = 1; i < 5; i++) cost += D[w[i-1] - 'A'][w[i] - 'A'] + 1;\n        return cost;\n    };\n\n    // Exact DP for a fixed string S: returns (cost, coordinates per character).\n    auto solve_dp = [&](const string& S) -> pair<long long, vector<Pos>> {\n        const long long LINF = (1LL<<60);\n        int L = (int)S.size();\n        vector<vector<short>> parent(L);\n        vector<long long> dpPrev, dpCur;\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            int mcur = (int)pos[c].size();\n            dpCur.assign(mcur, LINF);\n            parent[k].assign(mcur, (short)-1);\n\n            if (k == 0) {\n                for (int i = 0; i < mcur; i++) {\n                    dpCur[i] = (long long)manhattan(start, pos[c][i]) + 1;\n                }\n            } else {\n                int pc = S[k-1] - 'A';\n                int mprev = (int)pos[pc].size();\n                for (int i = 0; i < mcur; i++) {\n                    long long best = LINF;\n                    short bestj = -1;\n                    for (int j = 0; j < mprev; j++) {\n                        long long cand = dpPrev[j] + (long long)manhattan(pos[pc][j], pos[c][i]) + 1;\n                        if (cand < best) {\n                            best = cand;\n                            bestj = (short)j;\n                        }\n                    }\n                    dpCur[i] = best;\n                    parent[k][i] = bestj;\n                }\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        // Choose best ending\n        int lastC = S.back() - 'A';\n        int mend = (int)pos[lastC].size();\n        long long bestCost = (1LL<<60);\n        int bestIdx = 0;\n        for (int i = 0; i < mend; i++) {\n            if (dpPrev[i] < bestCost) {\n                bestCost = dpPrev[i];\n                bestIdx = i;\n            }\n        }\n\n        vector<Pos> path(L);\n        int idx = bestIdx;\n        for (int k = L-1; k >= 0; k--) {\n            int c = S[k] - 'A';\n            path[k] = pos[c][idx];\n            idx = parent[k][idx];\n        }\n        return {bestCost, path};\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)seed);\n\n    vector<string> candidates;\n\n    // Candidate 0: given order with overlaps\n    {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Candidate 1: nearest-neighbor order by last->first letter distance\n    {\n        int bestStart = 0;\n        int bestVal = INF;\n        for (int i = 0; i < M; i++) {\n            int v = approx_start_cost(t[i]);\n            if (v < bestVal) { bestVal = v; bestStart = i; }\n        }\n        vector<int> order;\n        order.reserve(M);\n        vector<char> used(M, 0);\n        order.push_back(bestStart);\n        used[bestStart] = 1;\n\n        for (int it = 1; it < M; it++) {\n            int cur = order.back();\n            char lastCh = t[cur][4];\n            int bestj = -1;\n            int bestd = INF;\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int d = D[lastCh - 'A'][t[j][0] - 'A'];\n                if (d < bestd) { bestd = d; bestj = j; }\n            }\n            used[bestj] = 1;\n            order.push_back(bestj);\n        }\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Candidate 2+: movement-aware greedy with random restarts\n    auto greedy_construct = [&](int tries, double noise0) {\n        vector<int> all(M);\n        iota(all.begin(), all.end(), 0);\n\n        // Precompute start cost ranking to pick better starts\n        vector<pair<int,int>> startRank;\n        startRank.reserve(M);\n        for (int i = 0; i < M; i++) startRank.push_back({approx_start_cost(t[i]), i});\n        sort(startRank.begin(), startRank.end());\n\n        uniform_real_distribution<double> uni01(0.0, 1.0);\n\n        for (int tr = 0; tr < tries; tr++) {\n            vector<int> rem = all;\n\n            // pick start among top-K\n            int K = 10;\n            int pick = startRank[min((int)startRank.size()-1, (int)(uni01(rng) * K))].second;\n\n            // remove pick from rem\n            {\n                int idx = -1;\n                for (int i = 0; i < (int)rem.size(); i++) if (rem[i] == pick) { idx = i; break; }\n                rem[idx] = rem.back();\n                rem.pop_back();\n            }\n\n            string S = t[pick];\n            char curLast = S.back();\n\n            string suffix4;\n            for (int i = max(0, (int)S.size() - 4); i < (int)S.size(); i++) suffix4.push_back(S[i]);\n\n            int stepsDone = 1;\n            while (!rem.empty()) {\n                double temp = noise0 * (1.0 - (double)stepsDone / (double)M);\n                int bestIdxInRem = 0;\n                double bestScore = 1e100;\n                int R = (int)rem.size();\n\n                for (int ri = 0; ri < R; ri++) {\n                    int widx = rem[ri];\n                    const string& w = t[widx];\n                    int l = overlap_len_suffix_prefix(suffix4, w);\n                    int base = approx_add_cost(curLast, w, l);\n\n                    double score = (double)base + temp * uni01(rng);\n                    if (score < bestScore) {\n                        bestScore = score;\n                        bestIdxInRem = ri;\n                    }\n                }\n\n                int widx = rem[bestIdxInRem];\n                const string& w = t[widx];\n                int l = overlap_len_suffix_prefix(suffix4, w);\n                string add = w.substr(l);\n                S += add;\n                update_suffix4(suffix4, add);\n                curLast = S.back();\n\n                rem[bestIdxInRem] = rem.back();\n                rem.pop_back();\n                stepsDone++;\n            }\n            candidates.push_back(S);\n        }\n    };\n\n    greedy_construct(12, 1.0);\n\n    // Random shuffle candidates\n    for (int k = 0; k < 3; k++) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        candidates.push_back(build_from_order_with_overlap(order));\n    }\n\n    // Evaluate candidates with exact DP and pick the best\n    long long bestCost = (1LL<<60);\n    vector<Pos> bestPath;\n    string bestS;\n\n    for (const string& S : candidates) {\n        if ((int)S.size() > 5000) continue; // must be within operation limit\n        auto [cost, path] = solve_dp(S);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestPath = std::move(path);\n            bestS = S;\n        }\n    }\n\n    // Output coordinates (one per operation)\n    for (auto &p : bestPath) {\n        cout << (int)p.r << ' ' << (int)p.c << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<uint64_t> bits;   // bitmask over N^2 cells\n    vector<int> cells;       // list of indices for output\n    int k;                   // number of cells\n    double obs;              // estimated true sum v(S)\n    double w;                // weight in objective\n    bool exact;              // drill => exact\n};\n\nstruct Placement {\n    int di, dj;\n    vector<uint64_t> bits;\n    vector<int> cells;           // indices\n    vector<int16_t> inter;       // intersection counts for each query (appended)\n    vector<int> neigh;           // neighbor placement indices (shifts)\n};\n\nstruct Field {\n    vector<Placement> ps;\n};\n\nstruct Solution {\n    vector<int> idx; // chosen placement per field\n    double cost;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    // deterministic hash mixing\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Solver {\n    int N, M;\n    double eps;\n    int N2;\n    int L; // number of uint64 blocks\n    int op_limit;\n    int ops = 0;\n\n    vector<Field> fields;\n    vector<Query> queries;\n\n    vector<int> drilledVal; // -1 unknown else exact v\n    int drilledCnt = 0;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, double eps_) : N(N_), M(M_), eps(eps_) {\n        N2 = N * N;\n        L = (N2 + 63) / 64;\n        op_limit = 2 * N2;\n        drilledVal.assign(N2, -1);\n        rng.seed((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    }\n\n    // --- interactive I/O ---\n    int drillCell(int i, int j) {\n        cout << \"q 1 \" << i << \" \" << j << endl;\n        ops++;\n        int v;\n        if (!(cin >> v)) exit(0);\n        return v;\n    }\n\n    int divineCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"q \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int y;\n        if (!(cin >> y)) exit(0);\n        return y;\n    }\n\n    int answerCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"a \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int ok;\n        if (!(cin >> ok)) exit(0);\n        return ok;\n    }\n\n    // reserve enough operations to drill all remaining cells + final answer\n    bool canSpendOps(int extra) const {\n        int remainingToDrill = N2 - drilledCnt;\n        // need remainingToDrill drills + 1 final answer after spending extra\n        return ops + extra + remainingToDrill + 1 <= op_limit;\n    }\n\n    // --- bit helpers ---\n    inline bool bitGet(const vector<uint64_t>& b, int idx) const {\n        return (b[idx >> 6] >> (idx & 63)) & 1ULL;\n    }\n    inline void bitSet(vector<uint64_t>& b, int idx) const {\n        b[idx >> 6] |= 1ULL << (idx & 63);\n    }\n    int popcountAnd(const vector<uint64_t>& a, const vector<uint64_t>& b) const {\n        int s = 0;\n        for (int t = 0; t < L; t++) s += __builtin_popcountll(a[t] & b[t]);\n        return s;\n    }\n\n    // --- build placements for each field ---\n    void buildPlacements(const vector<vector<pair<int,int>>>& shapes) {\n        fields.resize(M);\n        for (int f = 0; f < M; f++) {\n            const auto& shp = shapes[f];\n            int maxI = 0, maxJ = 0;\n            for (auto [x,y]: shp) {\n                maxI = max(maxI, x);\n                maxJ = max(maxJ, y);\n            }\n            int diMax = N - maxI - 1;\n            int djMax = N - maxJ - 1;\n            // map translation -> placement index\n            vector<vector<int>> mp(diMax+1, vector<int>(djMax+1, -1));\n\n            for (int di = 0; di <= diMax; di++) {\n                for (int dj = 0; dj <= djMax; dj++) {\n                    Placement p;\n                    p.di = di; p.dj = dj;\n                    p.bits.assign(L, 0ULL);\n                    p.cells.reserve(shp.size());\n                    for (auto [x,y]: shp) {\n                        int i = di + x;\n                        int j = dj + y;\n                        int idx = i*N + j;\n                        p.cells.push_back(idx);\n                        bitSet(p.bits, idx);\n                    }\n                    fields[f].ps.push_back(std::move(p));\n                    mp[di][dj] = (int)fields[f].ps.size()-1;\n                }\n            }\n            // neighbors by +/-1 shifts\n            for (auto &p: fields[f].ps) {\n                int di = p.di, dj = p.dj;\n                static int dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n                for (auto &d: dd) {\n                    int ndi = di + d[0], ndj = dj + d[1];\n                    if (0 <= ndi && ndi <= diMax && 0 <= ndj && ndj <= djMax) {\n                        int ni = mp[ndi][ndj];\n                        if (ni >= 0) p.neigh.push_back(ni);\n                    }\n                }\n            }\n        }\n    }\n\n    // --- add query + update all placement intersection arrays ---\n    void addQuery(const vector<int>& cellIdx, const vector<uint64_t>& bits, int k, int rawResp, bool exact) {\n        Query q;\n        q.bits = bits;\n        q.cells = cellIdx;\n        q.k = k;\n        q.exact = exact;\n\n        if (exact) {\n            q.obs = (double)rawResp;\n            q.w = 1e6; // very strong constraint\n        } else {\n            double coeff = 1.0 - 2.0 * eps;\n            double bias = (double)k * eps;\n            double est = (rawResp - bias) / coeff;\n            est = max(0.0, est);\n            est = min(est, (double)k * M);\n            q.obs = est;\n\n            double varx = (double)k * eps * (1.0 - eps);\n            // include rounding noise ~0.25 and small stabilizer\n            double vart = (varx + 0.25) / (coeff * coeff) + 1e-3;\n            q.w = 1.0 / vart;\n        }\n\n        queries.push_back(std::move(q));\n        int qid = (int)queries.size() - 1;\n\n        // append intersection counts for every placement\n        for (int f = 0; f < M; f++) {\n            for (auto &p: fields[f].ps) {\n                int c = popcountAnd(p.bits, queries[qid].bits);\n                p.inter.push_back((int16_t)c);\n            }\n        }\n    }\n\n    // --- query constructors ---\n    vector<int> cellsRow(int r) const {\n        vector<int> v; v.reserve(N);\n        for (int c = 0; c < N; c++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsCol(int c) const {\n        vector<int> v; v.reserve(N);\n        for (int r = 0; r < N; r++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsBlock(int r0, int r1, int c0, int c1) const {\n        vector<int> v;\n        for (int r = r0; r < r1; r++)\n            for (int c = c0; c < c1; c++)\n                v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsChecker(bool parity) const {\n        vector<int> v;\n        for (int r = 0; r < N; r++)\n            for (int c = 0; c < N; c++)\n                if (((r+c)&1) == (parity?1:0)) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> cellsRandomFixedSize(int k) {\n        vector<int> all(N2);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n        all.resize(max(2, k));\n        sort(all.begin(), all.end());\n        all.erase(unique(all.begin(), all.end()), all.end());\n        if ((int)all.size() < 2) {\n            all.clear();\n            all.push_back(0);\n            all.push_back(1);\n        }\n        return all;\n    }\n\n    vector<uint64_t> bitsFromCells(const vector<int>& v) const {\n        vector<uint64_t> b(L, 0ULL);\n        for (int idx: v) bitSet(b, idx);\n        return b;\n    }\n\n    // perform a divination query\n    void doDivination(const vector<int>& cellIdx) {\n        if ((int)cellIdx.size() < 2) return;\n        if (!canSpendOps(1)) return;\n\n        vector<pair<int,int>> out;\n        out.reserve(cellIdx.size());\n        for (int idx: cellIdx) out.push_back({idx / N, idx % N});\n        int y = divineCells(out);\n\n        vector<uint64_t> b = bitsFromCells(cellIdx);\n        addQuery(cellIdx, b, (int)cellIdx.size(), y, false);\n    }\n\n    // drill a cell and add exact constraint-query\n    void doDrill(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (!canSpendOps(1)) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<int> cellIdx = {idx};\n        vector<uint64_t> b(L, 0ULL);\n        bitSet(b, idx);\n        addQuery(cellIdx, b, 1, v, true);\n    }\n\n    // --- SA inference ---\n    Solution runSA(const vector<int>* startIdx, int iters) {\n        int Q = (int)queries.size();\n        vector<double> obs(Q), w(Q);\n        for (int q = 0; q < Q; q++) { obs[q] = queries[q].obs; w[q] = queries[q].w; }\n\n        vector<int> idx(M, 0);\n        if (startIdx) idx = *startIdx;\n        else {\n            for (int f = 0; f < M; f++) {\n                uniform_int_distribution<int> dist(0, (int)fields[f].ps.size() - 1);\n                idx[f] = dist(rng);\n            }\n        }\n\n        vector<int> pred(Q, 0);\n        vector<double> err(Q, 0.0);\n        // initialize err = pred - obs\n        for (int q = 0; q < Q; q++) err[q] = -obs[q];\n        for (int f = 0; f < M; f++) {\n            auto &pl = fields[f].ps[idx[f]];\n            for (int q = 0; q < Q; q++) {\n                int c = pl.inter[q];\n                pred[q] += c;\n                err[q] += c;\n            }\n        }\n        double cost = 0;\n        for (int q = 0; q < Q; q++) cost += w[q] * err[q] * err[q];\n\n        vector<int> bestIdx = idx;\n        double bestCost = cost;\n\n        double T0 = 2.0, T1 = 0.05;\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        uniform_int_distribution<int> fieldDist(0, M-1);\n\n        for (int it = 0; it < iters; it++) {\n            double t = (double)it / max(1, iters - 1);\n            double T = T0 * pow(T1 / T0, t);\n\n            int f = fieldDist(rng);\n            int cur = idx[f];\n            int nxt = cur;\n\n            auto &ps = fields[f].ps;\n            if (!ps[cur].neigh.empty() && ur(rng) < 0.6) {\n                // local neighbor\n                uniform_int_distribution<int> nd(0, (int)ps[cur].neigh.size() - 1);\n                nxt = ps[cur].neigh[nd(rng)];\n            } else {\n                uniform_int_distribution<int> pd(0, (int)ps.size() - 1);\n                nxt = pd(rng);\n            }\n            if (nxt == cur) continue;\n\n            double delta = 0.0;\n            auto &oldP = ps[cur];\n            auto &newP = ps[nxt];\n\n            for (int q = 0; q < Q; q++) {\n                int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                if (d == 0) continue;\n                double e = err[q];\n                delta += w[q] * (2.0 * e * d + 1.0 * d * d);\n            }\n\n            if (delta <= 0.0 || ur(rng) < exp(-delta / T)) {\n                // accept\n                for (int q = 0; q < Q; q++) {\n                    int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                    if (d == 0) continue;\n                    pred[q] += d;\n                    err[q] += d;\n                }\n                idx[f] = nxt;\n                cost += delta;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestIdx = idx;\n                }\n            }\n        }\n        return Solution{bestIdx, bestCost};\n    }\n\n    vector<Solution> sampleSolutions(int wantK) {\n        // SA restarts; keep best unique solutions\n        int restarts = 25;\n        int iters = 3500 + 30 * (int)queries.size();\n        iters = min(iters, 12000);\n\n        vector<Solution> sols;\n        sols.reserve(restarts);\n\n        // build a small pool of seeds from previous bests to stabilize (if any)\n        vector<vector<int>> seeds;\n        if (!sols.empty()) {\n            for (auto &s: sols) seeds.push_back(s.idx);\n        }\n\n        for (int r = 0; r < restarts; r++) {\n            vector<int> start;\n            bool useSeed = (!sols.empty() && (r % 5 == 0));\n            if (useSeed) {\n                start = sols[rng() % sols.size()].idx;\n                // random perturbation\n                for (int k = 0; k < 2; k++) {\n                    int f = rng() % M;\n                    int sz = (int)fields[f].ps.size();\n                    start[f] = rng() % sz;\n                }\n                auto res = runSA(&start, iters);\n                sols.push_back(std::move(res));\n            } else {\n                auto res = runSA(nullptr, iters);\n                sols.push_back(std::move(res));\n            }\n        }\n\n        sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b){ return a.cost < b.cost; });\n\n        unordered_set<uint64_t> seen;\n        vector<Solution> out;\n        for (auto &s: sols) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int x: s.idx) h = splitmix64(h ^ (uint64_t)x + 0x9e3779b97f4a7c15ULL);\n            if (seen.insert(h).second) out.push_back(s);\n            if ((int)out.size() >= wantK) break;\n        }\n        if (out.empty()) out.push_back(sols[0]);\n        return out;\n    }\n\n    // compute per-cell probability of being covered among given solutions\n    vector<double> computeCellProb(const vector<Solution>& sols) {\n        vector<int> cnt(N2, 0);\n        for (auto &s: sols) {\n            vector<uint64_t> uni(L, 0ULL);\n            for (int f = 0; f < M; f++) {\n                auto &pb = fields[f].ps[s.idx[f]].bits;\n                for (int t = 0; t < L; t++) uni[t] |= pb[t];\n            }\n            for (int idx = 0; idx < N2; idx++) {\n                if (bitGet(uni, idx)) cnt[idx]++;\n            }\n        }\n        vector<double> p(N2, 0.0);\n        for (int i = 0; i < N2; i++) p[i] = (double)cnt[i] / (double)sols.size();\n        // enforce drilled constraints (for decisions)\n        for (int i = 0; i < N2; i++) {\n            if (drilledVal[i] != -1) p[i] = (drilledVal[i] > 0) ? 1.0 : 0.0;\n        }\n        return p;\n    }\n\n    vector<pair<int,int>> buildAnswerFromProb(const vector<double>& p) const {\n        vector<pair<int,int>> ans;\n        ans.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            bool oil = (p[idx] >= 0.5);\n            if (drilledVal[idx] != -1) oil = (drilledVal[idx] > 0);\n            if (oil) ans.push_back({idx / N, idx % N});\n        }\n        return ans;\n    }\n\n    // --- main solve routine ---\n    void solve() {\n        // initial divinations (stop early if we must reserve operations)\n        // rows/cols\n        for (int i = 0; i < N; i++) doDivination(cellsRow(i));\n        for (int j = 0; j < N; j++) doDivination(cellsCol(j));\n\n        // blocks\n        int B = (N >= 18) ? 4 : (N >= 14) ? 3 : 2;\n        int step = (N + B - 1) / B;\n        for (int bi = 0; bi < B; bi++) {\n            for (int bj = 0; bj < B; bj++) {\n                int r0 = bi * step, r1 = min(N, (bi + 1) * step);\n                int c0 = bj * step, c1 = min(N, (bj + 1) * step);\n                auto v = cellsBlock(r0, r1, c0, c1);\n                if ((int)v.size() >= 2) doDivination(v);\n            }\n        }\n\n        // checkerboards\n        doDivination(cellsChecker(false));\n        doDivination(cellsChecker(true));\n\n        // random large subsets\n        int randQ = (N >= 16 ? 18 : 14);\n        for (int t = 0; t < randQ; t++) {\n            int k = (t % 2 == 0) ? (N2 / 2) : (N2 / 3);\n            doDivination(cellsRandomFixedSize(k));\n        }\n\n        // iterative: SA -> probabilities -> drill uncertain\n        int maxRounds = 6;\n        int totalDrillBudget = (N >= 16 ? 70 : 55);\n        int drilledThisPhase = 0;\n\n        for (int round = 0; round < maxRounds; round++) {\n            int wantK = 25;\n            auto sols = sampleSolutions(wantK);\n            auto prob = computeCellProb(sols);\n\n            // collect uncertain cells\n            const double pLow = 0.05, pHigh = 0.95;\n            vector<pair<double,int>> cand;\n            cand.reserve(N2);\n            for (int idx = 0; idx < N2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                double p = prob[idx];\n                if (pLow < p && p < pHigh) {\n                    cand.push_back({abs(p - 0.5), idx});\n                }\n            }\n            sort(cand.begin(), cand.end());\n\n            if (cand.empty()) {\n                // extra validation drills (small)\n                bool mismatch = false;\n                vector<pair<double,int>> zeroCand, oneCand;\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    double p = prob[idx];\n                    if (p <= pLow) zeroCand.push_back({-p, idx}); // closer to boundary first\n                    else if (p >= pHigh) oneCand.push_back({p, idx}); // smaller p first\n                }\n                sort(zeroCand.begin(), zeroCand.end());\n                sort(oneCand.begin(), oneCand.end());\n\n                int checks = 0;\n                for (int t = 0; t < (int)zeroCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = zeroCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] > 0) mismatch = true;\n                }\n                checks = 0;\n                for (int t = 0; t < (int)oneCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = oneCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] == 0) mismatch = true;\n                }\n                if (mismatch) continue;\n\n                // attempt answer (keeping fallback possible)\n                if (canSpendOps(1)) {\n                    auto ans = buildAnswerFromProb(prob);\n                    int ok = answerCells(ans);\n                    if (ok == 1) return;\n                    // if wrong, break to fallback\n                    break;\n                } else {\n                    break;\n                }\n            } else {\n                // drill the most uncertain cells (batch)\n                int batch = min(10, (int)cand.size());\n                for (int t = 0; t < batch; t++) {\n                    if (drilledThisPhase >= totalDrillBudget) break;\n                    if (!canSpendOps(1)) break;\n                    doDrill(cand[t].second);\n                    drilledThisPhase++;\n                }\n            }\n        }\n\n        // fallback: drill everything remaining, answer exactly\n        vector<pair<int,int>> oilCells;\n        oilCells.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] == -1) doDrill(idx);\n            if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n        }\n        (void)answerCells(oilCells);\n        return;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    double eps;\n    cin >> N >> M >> eps;\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; k++) {\n        int d;\n        cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; t++) {\n            int i, j;\n            cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    Solver solver(N, M, eps);\n    solver.buildPlacements(shapes);\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n    const int HALL = 1000; // fixed by statement\n\n    vector<int> prevH(N, HALL / N);\n    prevH.back() += HALL - accumulate(prevH.begin(), prevH.end(), 0);\n\n    for (int d = 0; d < D; d++) {\n        vector<int> a(N);\n        for (int k = 0; k < N; k++) cin >> a[k];\n\n        // Minimum heights to avoid shortage with full width=1000 stripes\n        vector<int> need(N);\n        long long sumNeed = 0;\n        for (int k = 0; k < N; k++) {\n            need[k] = max(1, (a[k] + HALL - 1) / HALL);\n            sumNeed += need[k];\n        }\n\n        vector<int> h(N);\n\n        if (sumNeed <= HALL) {\n            // No shortage possible. Try to keep internal boundaries close to previous day.\n            // Internal boundaries depend only on h[0..N-2], last stripe absorbs remaining height.\n            long long cap = HALL - need[N - 1]; // max sum of h[0..N-2] while keeping last >= need_last\n\n            long long sumFirst = 0;\n            for (int k = 0; k <= N - 2; k++) {\n                h[k] = max(need[k], prevH[k]); // keep previous if it doesn't violate need\n                sumFirst += h[k];\n            }\n\n            // If too large, reduce from the end first (disturbs fewer earlier boundaries)\n            if (sumFirst > cap) {\n                long long excess = sumFirst - cap;\n                for (int k = N - 2; k >= 0 && excess > 0; k--) {\n                    int reducible = h[k] - need[k];\n                    int dec = (int)min<long long>(excess, reducible);\n                    h[k] -= dec;\n                    excess -= dec;\n                    sumFirst -= dec;\n                }\n                // Now sumFirst should be exactly cap\n            }\n\n            h[N - 1] = (int)(HALL - sumFirst);\n            // Guarantee last >= need_last\n            if (h[N - 1] < need[N - 1]) {\n                // Should not happen, but keep safe: fallback to simple fill-last.\n                h = need;\n                h[N - 1] += (int)(HALL - sumNeed);\n            }\n\n        } else {\n            // Shortage unavoidable with full-width stripes.\n            // Start from need and decrement exactly T units with minimum marginal penalty increase.\n            h = need;\n            int T = (int)(sumNeed - HALL);\n\n            // min-heap by (delta, -k): smaller delta first, for ties prefer larger k\n            using P = pair<int,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n\n            for (int k = 0; k < N; k++) {\n                if (h[k] <= 1) continue;\n                int r = a[k] % HALL;\n                int delta = (r == 0 ? HALL : r); // first decrement cost from need to need-1\n                pq.push({delta, -k});\n            }\n\n            for (int t = 0; t < T; t++) {\n                if (pq.empty()) break; // should not happen\n                auto [delta, nk] = pq.top();\n                pq.pop();\n                int k = -nk;\n                h[k]--;\n                if (h[k] > 1) {\n                    // further decrements always add 1000 shortage\n                    pq.push({HALL, -k});\n                }\n            }\n\n            // Ensure sum == 1000 by adjusting last if something unexpected happened\n            int sumH = accumulate(h.begin(), h.end(), 0);\n            if (sumH != HALL) {\n                h.back() += (HALL - sumH);\n                if (h.back() <= 0) h.back() = 1; // safety\n            }\n        }\n\n        // Output rectangles as stacked horizontal stripes [y,y+h) x [0,1000]\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            int y2 = y + h[k];\n            // ensure within bounds (should end at 1000)\n            y2 = min(y2, HALL);\n            cout << y << \" \" << 0 << \" \" << y2 << \" \" << HALL << \"\\n\";\n            y = y2;\n        }\n\n        prevH = h;\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline uint32_t addmod(uint32_t a, uint32_t b) {\n    uint32_t s = a + b;\n    if (s >= MOD) s -= MOD;\n    return s;\n}\nstatic inline uint32_t negmod(uint32_t a) {\n    return a ? (MOD - a) : 0u;\n}\n\nstruct Action {\n    uint8_t m, p, q;\n    uint8_t idx[9];   // affected cell indices 0..80\n    uint32_t val[9];  // added values mod MOD\n};\n\nstruct DeltaBuf {\n    array<uint32_t, 81> delta{};\n    array<int, 81> vis{};\n    int iter = 1;\n    uint8_t cells[18];\n    int cnt = 0;\n\n    inline void clear() {\n        iter++;\n        if (iter == INT_MAX) { // very unlikely, but safe\n            iter = 1;\n            vis.fill(0);\n        }\n        cnt = 0;\n    }\n    inline void addCell(uint8_t c, uint32_t dv) {\n        if (dv == 0) return;\n        if (vis[c] != iter) {\n            vis[c] = iter;\n            delta[c] = dv;\n            cells[cnt++] = c;\n        } else {\n            delta[c] = addmod(delta[c], dv);\n        }\n    }\n};\n\nstatic inline int64_t add_gain_only(const Action &a, const array<uint32_t,81> &res) {\n    int64_t d = 0;\n    for (int k = 0; k < 9; k++) {\n        uint8_t c = a.idx[k];\n        uint32_t r = res[c];\n        uint32_t nr = r + a.val[k];\n        if (nr >= MOD) nr -= MOD;\n        d += (int64_t)nr - (int64_t)r;\n    }\n    return d;\n}\n\nstatic inline int64_t compute_change(int oldId, int newId,\n                                    const vector<Action> &actions,\n                                    const array<uint32_t,81> &res,\n                                    DeltaBuf &buf) {\n    buf.clear();\n    if (oldId != -1) {\n        const auto &a = actions[oldId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], negmod(a.val[k]));\n    }\n    if (newId != -1) {\n        const auto &a = actions[newId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], a.val[k]);\n    }\n    int64_t dscore = 0;\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        dscore += (int64_t)nr - (int64_t)r;\n    }\n    return dscore;\n}\n\nstatic inline void apply_change(const DeltaBuf &buf, array<uint32_t,81> &res) {\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        res[c] = nr;\n    }\n}\n\nstatic inline int64_t score_of(const array<uint32_t,81> &res) {\n    int64_t s = 0;\n    for (uint32_t v : res) s += v;\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K; // N=9,M=20,K=81\n\n    array<uint32_t,81> a0{};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        uint64_t x; cin >> x;\n        a0[i*N + j] = (uint32_t)(x % MOD);\n    }\n\n    vector<array<uint32_t,9>> stamps(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n            uint64_t x; cin >> x;\n            stamps[m][i*3 + j] = (uint32_t)(x % MOD);\n        }\n    }\n\n    // Precompute actions\n    vector<Action> actions;\n    actions.reserve(M * (N-2) * (N-2));\n    // mapping: stamp m, pos (p*7+q) -> action id\n    array<array<int, 49>, 20> idOf{};\n    for (int m = 0; m < M; m++) for (int pos = 0; pos < 49; pos++) idOf[m][pos] = -1;\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action act;\n                act.m = (uint8_t)m;\n                act.p = (uint8_t)p;\n                act.q = (uint8_t)q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n                    int bi = p + i, bj = q + j;\n                    act.idx[t] = (uint8_t)(bi * N + bj);\n                    act.val[t] = stamps[m][i*3 + j];\n                    t++;\n                }\n                int id = (int)actions.size();\n                actions.push_back(act);\n                int pos = p * 7 + q;\n                idOf[m][pos] = id;\n            }\n        }\n    }\n    const int A = (int)actions.size(); // 980\n\n    // Seed RNG input-dependent\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 81; i++) seed = seed * 1000003ULL + a0[i];\n    XorShift64 rng(seed);\n\n    // exp lookup for x in [-20,0]\n    static vector<double> expTab;\n    if (expTab.empty()) {\n        const int STEPS = 8192;\n        expTab.resize(STEPS + 1);\n        for (int i = 0; i <= STEPS; i++) {\n            double x = -20.0 * (double)i / (double)STEPS;\n            expTab[i] = exp(x);\n        }\n    }\n    auto exp_lookup = [&](double x)->double { // x in [-20,0]\n        if (x <= -20.0) return 0.0;\n        if (x >= 0.0) return 1.0;\n        const int STEPS = (int)expTab.size() - 1;\n        int idx = (int)llround((-x) * (double)STEPS / 20.0);\n        if (idx < 0) idx = 0;\n        if (idx > STEPS) idx = STEPS;\n        return expTab[idx];\n    };\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n\n    auto elapsedSec = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    auto best_stamp_for_pos = [&](int pos, const array<uint32_t,81> &res)->int {\n        int bestId = -1;\n        int64_t bestGain = LLONG_MIN;\n        for (int m = 0; m < M; m++) {\n            int id = idOf[m][pos];\n            int64_t g = add_gain_only(actions[id], res);\n            if (g > bestGain) {\n                bestGain = g;\n                bestId = id;\n            }\n        }\n        return bestId;\n    };\n\n    // Build solution from ops\n    auto rebuild = [&](const vector<int> &ops, array<uint32_t,81> &res)->int64_t {\n        res = a0;\n        for (int id : ops) {\n            if (id == -1) continue;\n            const auto &a = actions[id];\n            for (int k = 0; k < 9; k++) {\n                uint8_t c = a.idx[k];\n                uint32_t nr = res[c] + a.val[k];\n                if (nr >= MOD) nr -= MOD;\n                res[c] = nr;\n            }\n        }\n        return score_of(res);\n    };\n\n    // One run: init then SA+LNS, return best\n    vector<int> globalBestOps(K, -1);\n    int64_t globalBestScore = score_of(a0);\n\n    DeltaBuf buf;\n\n    auto do_run = [&](int mode, double endTimeSec) {\n        // mode 0: greedy with small randomness\n        // mode 1: randomized by position (choose pos random, best stamp for that pos wrt current)\n        vector<int> ops(K, -1);\n        array<uint32_t,81> res = a0;\n        int64_t score = score_of(res);\n\n        if (mode == 0) {\n            // Greedy fill, but sometimes pick among top few to diversify\n            for (int slot = 0; slot < K; slot++) {\n                int best1 = -1, best2 = -1, best3 = -1;\n                int64_t g1 = 0, g2 = 0, g3 = 0;\n                for (int id = 0; id < A; id++) {\n                    int64_t g = add_gain_only(actions[id], res);\n                    if (g > g1) {\n                        best3 = best2; g3 = g2;\n                        best2 = best1; g2 = g1;\n                        best1 = id;    g1 = g;\n                    } else if (g > g2) {\n                        best3 = best2; g3 = g2;\n                        best2 = id;    g2 = g;\n                    } else if (g > g3) {\n                        best3 = id;    g3 = g;\n                    }\n                }\n                if (best1 == -1 || g1 <= 0) break;\n                int pick = best1;\n                // 15%: pick best2/3 if close\n                if (rng.nextInt(100) < 15) {\n                    int r = rng.nextInt(3);\n                    if (r == 1 && best2 != -1) pick = best2;\n                    if (r == 2 && best3 != -1) pick = best3;\n                }\n                ops[slot] = pick;\n                const auto &a = actions[pick];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n                score += add_gain_only(a, res); // WRONG if used after applying; avoid; keep score by recomputing delta before apply\n                // Fix: we won't use this broken score update; recompute after greedy loop.\n                // (We keep this line harmless by overwriting score below.)\n            }\n            score = score_of(res);\n        } else {\n            // Randomized position-based construction\n            for (int slot = 0; slot < K; slot++) {\n                int pos = rng.nextInt(49);\n                int id = best_stamp_for_pos(pos, res);\n                // small chance to take random stamp instead\n                if (rng.nextInt(100) < 10) {\n                    int m = rng.nextInt(M);\n                    id = idOf[m][pos];\n                }\n                ops[slot] = id;\n                const auto &a = actions[id];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n            }\n            score = score_of(res);\n        }\n\n        // track local best\n        vector<int> bestOps = ops;\n        int64_t bestScore = score;\n        array<uint32_t,81> bestRes = res;\n\n        // SA parameters\n        const double T0 = 2.0e9;\n        const double T1 = 2.0e6;\n        const double logRatio = log(T1 / T0);\n\n        double lastCheck = elapsedSec();\n        double T = T0;\n        uint64_t iters = 0;\n\n        auto accept_move = [&](int64_t d)->bool {\n            if (d >= 0) return true;\n            double x = (double)d / T; // negative\n            double prob = exp_lookup(x);\n            return rng.nextDouble() < prob;\n        };\n\n        // SA loop\n        while (true) {\n            iters++;\n\n            if ((iters & 2047ull) == 0) {\n                double e = elapsedSec();\n                if (e >= endTimeSec) break;\n                double prog = (e - lastCheck) / max(1e-9, (endTimeSec - lastCheck)); // not great; use global progress instead\n                (void)prog;\n                double globalProg = min(1.0, e / endTimeSec);\n                T = T0 * exp(logRatio * globalProg);\n            }\n\n            int moveType = rng.nextInt(100);\n            if (moveType < 70) {\n                // 1-slot replace\n                int slot = rng.nextInt(K);\n                int oldId = ops[slot];\n\n                int newId = -1;\n                int r = rng.nextInt(100);\n\n                if (r < 10) {\n                    newId = -1;\n                } else if (r < 40) {\n                    // random action\n                    newId = rng.nextInt(A);\n                } else if (r < 65) {\n                    // best stamp for random pos\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1 && r < 85) {\n                    // same position, best stamp\n                    int pos = actions[oldId].p * 7 + actions[oldId].q;\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1) {\n                    // same stamp, random position\n                    int m = actions[oldId].m;\n                    int pos = rng.nextInt(49);\n                    newId = idOf[m][pos];\n                } else {\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                }\n\n                if (newId == oldId) continue;\n\n                int64_t d = compute_change(oldId, newId, actions, res, buf);\n                if (accept_move(d)) {\n                    apply_change(buf, res);\n                    score += d;\n                    ops[slot] = newId;\n\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else if (moveType < 90) {\n                // 2-slot replace\n                int s1 = rng.nextInt(K);\n                int s2 = rng.nextInt(K);\n                if (s1 == s2) continue;\n                int old1 = ops[s1], old2 = ops[s2];\n\n                int new1, new2;\n                // propose using strong candidates sometimes\n                auto propose = [&](int oldId)->int {\n                    int rr = rng.nextInt(100);\n                    if (rr < 10) return -1;\n                    if (rr < 35) return rng.nextInt(A);\n                    if (rr < 70) {\n                        int pos = rng.nextInt(49);\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    if (oldId != -1) {\n                        int pos = actions[oldId].p * 7 + actions[oldId].q;\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    int pos = rng.nextInt(49);\n                    return best_stamp_for_pos(pos, res);\n                };\n                new1 = propose(old1);\n                new2 = propose(old2);\n                if (new1 == old1 && new2 == old2) continue;\n\n                // apply combined by sequential compute in a temp copy (cheap, 81 cells)\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // change slot1\n                int64_t d1 = compute_change(old1, new1, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d1;\n                // change slot2 (note: use updated tmpRes)\n                int64_t d2 = compute_change(old2, new2, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d2;\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    res = tmpRes;\n                    score = tmpScore;\n                    ops[s1] = new1;\n                    ops[s2] = new2;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else {\n                // LNS: remove t random slots, then greedily refill\n                int t = 6 + rng.nextInt(7); // 6..12\n                vector<int> idx(K);\n                iota(idx.begin(), idx.end(), 0);\n                for (int i = 0; i < t; i++) {\n                    int j = i + rng.nextInt(K - i);\n                    swap(idx[i], idx[j]);\n                }\n                idx.resize(t);\n\n                vector<int> tmpOps = ops;\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // remove chosen slots\n                for (int slot : idx) {\n                    int oldId = tmpOps[slot];\n                    if (oldId == -1) continue;\n                    int64_t d = compute_change(oldId, -1, actions, tmpRes, buf);\n                    apply_change(buf, tmpRes);\n                    tmpScore += d;\n                    tmpOps[slot] = -1;\n                }\n\n                // greedy refill chosen slots (leave empty if bestGain <= 0 most of the time)\n                for (int slot : idx) {\n                    int bestId = -1;\n                    int64_t bestG = LLONG_MIN;\n\n                    // Use a mix: try best over all actions, but we can speed by also trying best-per-pos sometimes.\n                    // Since A=980 small, full scan is fine here.\n                    for (int id = 0; id < A; id++) {\n                        int64_t g = add_gain_only(actions[id], tmpRes);\n                        if (g > bestG) { bestG = g; bestId = id; }\n                    }\n\n                    if (bestId != -1) {\n                        bool take = (bestG > 0) || (rng.nextInt(100) < 10); // 10% take even if <=0\n                        if (take) {\n                            const auto &a = actions[bestId];\n                            for (int k = 0; k < 9; k++) {\n                                uint8_t c = a.idx[k];\n                                uint32_t nr = tmpRes[c] + a.val[k];\n                                if (nr >= MOD) nr -= MOD;\n                                tmpRes[c] = nr;\n                            }\n                            tmpOps[slot] = bestId;\n                            // update tmpScore by exact delta\n                            // (use add_gain_only on original res would be wrong; recompute via direct diff)\n                            // easiest: recompute score delta for 9 cells:\n                            // but we already updated tmpRes; so compute delta by subtracting old via storing old values:\n                            // keep it simple: compute after all refills (81 cells only).\n                        }\n                    }\n                }\n                tmpScore = score_of(tmpRes);\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    ops.swap(tmpOps);\n                    res = tmpRes;\n                    score = tmpScore;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            }\n        }\n\n        // Final local refinement: repeat 1-opt until no improvement or time\n        ops = bestOps;\n        score = rebuild(ops, res);\n        bool any = true;\n        while (any && elapsedSec() < endTimeSec) {\n            any = false;\n            vector<int> order(K);\n            iota(order.begin(), order.end(), 0);\n            // lightweight shuffle\n            for (int i = 0; i < K; i++) swap(order[i], order[rng.nextInt(K)]);\n\n            for (int t = 0; t < K; t++) {\n                if (elapsedSec() >= endTimeSec) break;\n                int slot = order[t];\n                int oldId = ops[slot];\n\n                int bestNew = oldId;\n                int64_t bestD = 0;\n                DeltaBuf bestBufLocal;\n\n                // try empty\n                {\n                    int64_t d = compute_change(oldId, -1, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = -1;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                // try all actions\n                for (int id = 0; id < A; id++) {\n                    if (id == oldId) continue;\n                    int64_t d = compute_change(oldId, id, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = id;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                if (bestNew != oldId) {\n                    apply_change(bestBufLocal, res);\n                    score += bestD;\n                    ops[slot] = bestNew;\n                    any = true;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                    }\n                }\n            }\n        }\n\n        if (bestScore > globalBestScore) {\n            globalBestScore = bestScore;\n            globalBestOps = bestOps;\n        }\n    };\n\n    // Time budgeting: 2 runs + final polishing built-in each run\n    // Run 1: greedy-ish init\n    do_run(0, min(TL, 1.30));\n    // Run 2: randomized init, use remaining time\n    do_run(1, TL);\n\n    // Output\n    vector<tuple<int,int,int>> out;\n    out.reserve(K);\n    for (int id : globalBestOps) {\n        if (id == -1) continue;\n        const auto &a = actions[id];\n        out.emplace_back((int)a.m, (int)a.p, (int)a.q);\n    }\n    cout << out.size() << \"\\n\";\n    for (auto &[m,p,q] : out) {\n        cout << m << \" \" << p << \" \" << q << \"\\n\";\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 5;\nstatic const int MAX_TURNS = 10000;\n\nstruct Solver {\n    int n;\n    int A[N][N];\n\n    // grid container id or -1\n    int grid[N][N];\n\n    // for each receiving row r: how many have been spawned so far (0..N)\n    int spawned[N];\n\n    // per dispatch-group row t: bitmask of dispatched indices (0..4)\n    int dispMask[N];\n    int dispatchedCount = 0;\n\n    // origin info for each container id\n    int origRow[N*N], origIdx[N*N];\n\n    struct Crane {\n        int r=0, c=0;\n        bool alive=true;\n        bool holding=false;\n        int held=-1;\n        bool large=false;\n    };\n\n    Crane cranes[N]; // 0 is large, 1..4 small\n\n    vector<string> out; // 5 strings\n    int turn = 0;\n\n    Solver(int n_, const vector<vector<int>>& Ain) : n(n_), out(N, \"\") {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) A[i][j] = Ain[i][j];\n        // origin map\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            origRow[A[i][j]] = i;\n            origIdx[A[i][j]] = j;\n        }\n        // init grid empty\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) grid[i][j] = -1;\n        for(int i=0;i<N;i++) spawned[i] = 0;\n        for(int i=0;i<N;i++) dispMask[i] = 0;\n\n        // init cranes\n        for(int i=0;i<N;i++){\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].alive = true;\n            cranes[i].holding = false;\n            cranes[i].held = -1;\n            cranes[i].large = (i==0);\n        }\n    }\n\n    int expIndex(int t) const {\n        for(int k=0;k<N;k++){\n            if(((dispMask[t] >> k) & 1) == 0) return k;\n        }\n        return N; // done\n    }\n\n    int expectedId(int t) const {\n        int k = expIndex(t);\n        if(k>=N) return -1;\n        return 5*t + k;\n    }\n\n    pair<int,int> findPos(int id) const {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j] == id) return {i,j};\n        }\n        return {-1,-1};\n    }\n\n    bool holdingCraneAt(int r, int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].holding && cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n\n    // allowed storage: any cell with col in [1..3], plus (row,0) only if spawned[row]==N (gate exhausted)\n    bool isAllowedStorageCell(int r, int c) const {\n        if(c==4) return false; // dispatch column not for storage\n        if(c==0 && spawned[r] < N) return false; // active receiving gate: don't block\n        return true;\n    }\n\n    int countAllowedStorageEmpty() const {\n        int cnt=0;\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j]!=-1) continue;\n            if(!isAllowedStorageCell(i,j)) continue;\n            // avoid dispatch col already excluded\n            cnt++;\n        }\n        return cnt;\n    }\n\n    int invCostIfDispatch(int id) const {\n        int t = id/5;\n        int idx = id%5;\n        int cost = 0;\n        for(int k=0;k<idx;k++){\n            if(((dispMask[t] >> k) & 1) == 0) cost++;\n        }\n        return cost;\n    }\n\n    pair<int,int> chooseStorageCellNearest(int sr, int sc) const {\n        int bestD = INT_MAX;\n        pair<int,int> best = {-1,-1};\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            if(grid[i][j]!=-1) continue;\n            if(!isAllowedStorageCell(i,j)) continue;\n            int d = abs(sr-i) + abs(sc-j);\n            if(d < bestD){\n                bestD = d;\n                best = {i,j};\n            }\n        }\n        return best;\n    }\n\n    void step(char actLarge){\n        if(turn >= MAX_TURNS) return;\n\n        // decide actions for all cranes\n        char act[N];\n        for(int k=0;k<N;k++){\n            if(k==0) act[k] = actLarge;\n            else act[k] = (turn==0 ? 'B' : '.'); // bomb small cranes immediately\n        }\n\n        for(int k=0;k<N;k++) out[k].push_back(act[k]);\n\n        // 1) receiving\n        for(int r=0;r<N;r++){\n            if(spawned[r] >= N) continue;\n            if(grid[r][0] != -1) continue;\n            if(holdingCraneAt(r,0)) continue;\n            grid[r][0] = A[r][spawned[r]];\n            spawned[r]++;\n        }\n\n        // 2) actions simultaneously (generic, though after turn0 only crane0 alive)\n        // compute destinations\n        pair<int,int> startPos[N], destPos[N];\n        bool willBomb[N];\n        for(int k=0;k<N;k++){\n            startPos[k] = {cranes[k].r, cranes[k].c};\n            willBomb[k] = false;\n            destPos[k] = startPos[k];\n            if(!cranes[k].alive){\n                // must be '.'\n                continue;\n            }\n            char a = act[k];\n            if(a=='B'){\n                // bomb allowed only if not holding\n                if(cranes[k].holding){\n                    // illegal, but avoid WA in judge by doing nothing (should not happen)\n                    a='.';\n                } else {\n                    willBomb[k] = true;\n                }\n            } else if(a=='U' || a=='D' || a=='L' || a=='R'){\n                int nr = cranes[k].r;\n                int nc = cranes[k].c;\n                if(a=='U') nr--;\n                if(a=='D') nr++;\n                if(a=='L') nc--;\n                if(a=='R') nc++;\n                // bounds\n                if(0 <= nr && nr < N && 0 <= nc && nc < N){\n                    // small crane carrying restriction\n                    if(!cranes[k].large && cranes[k].holding){\n                        if(grid[nr][nc] != -1){\n                            // illegal, cancel move\n                            nr = cranes[k].r;\n                            nc = cranes[k].c;\n                        }\n                    }\n                    destPos[k] = {nr,nc};\n                }\n            }\n        }\n\n        // collision check after move among non-bombed alive cranes\n        // treat bombed cranes as removed\n        {\n            map<pair<int,int>, int> occ;\n            for(int k=0;k<N;k++){\n                if(!cranes[k].alive) continue;\n                if(willBomb[k]) continue;\n                auto d = destPos[k];\n                if(occ.count(d)){\n                    // invalid; in this solution it shouldn't happen (single crane after turn0)\n                    // resolve by forcing this crane to stay\n                    destPos[k] = startPos[k];\n                } else occ[d] = k;\n            }\n        }\n        // swap check\n        for(int i=0;i<N;i++) for(int j=i+1;j<N;j++){\n            if(!cranes[i].alive || !cranes[j].alive) continue;\n            if(willBomb[i] || willBomb[j]) continue;\n            if(destPos[i]==startPos[j] && destPos[j]==startPos[i] && destPos[i]!=destPos[j]){\n                // invalid swap; avoid by stopping j\n                destPos[j] = startPos[j];\n            }\n        }\n\n        // apply moves\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(willBomb[k]) continue;\n            cranes[k].r = destPos[k].first;\n            cranes[k].c = destPos[k].second;\n        }\n\n        // apply non-move actions (P/Q/B) (movement-only already applied)\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a = act[k];\n            if(a=='B'){\n                if(!cranes[k].holding){\n                    cranes[k].alive = false;\n                }\n            } else if(a=='P'){\n                int r = cranes[k].r, c = cranes[k].c;\n                if(!cranes[k].holding && grid[r][c] != -1){\n                    cranes[k].holding = true;\n                    cranes[k].held = grid[r][c];\n                    grid[r][c] = -1;\n                }\n            } else if(a=='Q'){\n                int r = cranes[k].r, c = cranes[k].c;\n                if(cranes[k].holding && grid[r][c] == -1){\n                    grid[r][c] = cranes[k].held;\n                    cranes[k].holding = false;\n                    cranes[k].held = -1;\n                }\n            }\n        }\n\n        // 3) dispatch\n        for(int r=0;r<N;r++){\n            if(grid[r][4] != -1){\n                int id = grid[r][4];\n                grid[r][4] = -1;\n                // mark dispatched\n                int t = id/5;\n                int idx = id%5;\n                if(((dispMask[t] >> idx) & 1) == 0){\n                    dispMask[t] |= (1<<idx);\n                    dispatchedCount++;\n                } else {\n                    // should not happen (duplicate dispatch), ignore\n                }\n            }\n        }\n\n        turn++;\n    }\n\n    void moveTo(int tr, int tc){\n        while(turn < MAX_TURNS && cranes[0].alive && (cranes[0].r != tr || cranes[0].c != tc)){\n            int r = cranes[0].r, c = cranes[0].c;\n            if(r < tr) step('D');\n            else if(r > tr) step('U');\n            else if(c < tc) step('R');\n            else if(c > tc) step('L');\n        }\n    }\n\n    void dispatchId(int id){\n        auto p = findPos(id);\n        if(p.first == -1) return; // not on grid (not spawned yet)\n        // go pick\n        moveTo(p.first, p.second);\n        // ensure container still here\n        if(turn >= MAX_TURNS) return;\n        if(cranes[0].holding) return;\n        if(grid[cranes[0].r][cranes[0].c] != id) return;\n        step('P');\n        if(turn >= MAX_TURNS) return;\n        // go to correct dispatch gate\n        int t = id/5;\n        moveTo(t, 4);\n        if(turn >= MAX_TURNS) return;\n        step('Q'); // dispatched in same turn end\n    }\n\n    void storeHeldToSomewhere(){\n        if(!cranes[0].holding) return;\n        auto s = chooseStorageCellNearest(cranes[0].r, cranes[0].c);\n        if(s.first == -1) return; // no space\n        moveTo(s.first, s.second);\n        if(turn >= MAX_TURNS) return;\n        step('Q');\n    }\n\n    void clearOneFromGate(int r){\n        // go to (r,0) and remove the current gate container by dispatching if good else storing/dispatching\n        moveTo(r, 0);\n        if(turn >= MAX_TURNS) return;\n\n        if(grid[r][0] == -1){\n            // maybe wait a turn for spawn if any\n            step('.');\n            return;\n        }\n        if(cranes[0].holding) return;\n        int id = grid[r][0];\n\n        step('P');\n        if(turn >= MAX_TURNS) return;\n        id = cranes[0].held;\n\n        int t = id/5;\n        int idx = id%5;\n        int e = expIndex(t);\n\n        int empty = countAllowedStorageEmpty();\n\n        // If it's exactly next expected for its group -> dispatch now\n        if(idx == e){\n            moveTo(t, 4);\n            if(turn >= MAX_TURNS) return;\n            step('Q');\n            return;\n        }\n\n        // If storage is available, store; otherwise dispatch out-of-order to free space\n        if(empty >= 2){\n            storeHeldToSomewhere();\n        } else {\n            moveTo(t, 4);\n            if(turn >= MAX_TURNS) return;\n            step('Q');\n        }\n    }\n\n    int chooseBestOutOfOrderDispatchCandidate() const {\n        // choose container on grid minimizing (invCost, distance, bonus for being at active gate)\n        int bestId = -1;\n        long long bestScore = (1LL<<60);\n        int cr = cranes[0].r, cc = cranes[0].c;\n\n        for(int i=0;i<N;i++) for(int j=0;j<4;j++){ // never any container at col4 in our sim\n            int id = grid[i][j];\n            if(id == -1) continue;\n            int inv = invCostIfDispatch(id);\n            int t = id/5;\n            int dist = abs(cr-i)+abs(cc-j) + abs(i-t)+abs(j-4);\n            long long score = 100000LL*inv + 10LL*dist;\n\n            // bonus: freeing an active gate is useful\n            if(j==0 && spawned[i] < N) score -= 50;\n\n            if(score < bestScore){\n                bestScore = score;\n                bestId = id;\n            }\n        }\n        return bestId;\n    }\n\n    int chooseExpectedToUncover() const {\n        // pick an expected container not yet on grid, whose origin needs fewest clears\n        int bestD = -1;\n        pair<int,int> bestKey = {INT_MAX, INT_MAX};\n        int cr = cranes[0].r, cc = cranes[0].c;\n\n        for(int t=0;t<N;t++){\n            int d = expectedId(t);\n            if(d == -1) continue; // group done\n            auto p = findPos(d);\n            if(p.first != -1) continue; // already on grid\n\n            int r = origRow[d];\n            int oi = origIdx[d];\n\n            // spawned[r] is #spawned so far (0..5).\n            // If d not spawned yet, oi >= spawned[r].\n            int needClears = 0;\n            if(spawned[r] <= oi) needClears = oi - spawned[r] + 1;\n            else needClears = 0; // already spawned, should be on grid, but handle\n\n            int distGate = abs(cr-r)+abs(cc-0);\n            pair<int,int> key = {needClears, distGate};\n            if(key < bestKey){\n                bestKey = key;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\n    void run(){\n        // Turn 0: spawn first containers and bomb small cranes\n        step('.');\n\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            // 1) if any expected container exists on grid, dispatch it (choose nearest)\n            int bestExpId = -1;\n            int bestDist = INT_MAX;\n            int cr = cranes[0].r, cc = cranes[0].c;\n\n            for(int t=0;t<N;t++){\n                int d = expectedId(t);\n                if(d == -1) continue;\n                auto p = findPos(d);\n                if(p.first == -1) continue;\n                int dist = abs(cr-p.first) + abs(cc-p.second) + abs(p.first - t) + abs(p.second - 4);\n                if(dist < bestDist){\n                    bestDist = dist;\n                    bestExpId = d;\n                }\n            }\n\n            if(bestExpId != -1){\n                dispatchId(bestExpId);\n                continue;\n            }\n\n            // 2) if storage is tight, dispatch something (min extra inversions)\n            int empty = countAllowedStorageEmpty();\n            if(empty <= 1){\n                int cand = chooseBestOutOfOrderDispatchCandidate();\n                if(cand != -1){\n                    dispatchId(cand);\n                    continue;\n                }\n            }\n\n            // 3) otherwise, try to uncover some expected container by clearing its origin gate\n            int d = chooseExpectedToUncover();\n            if(d != -1){\n                int r = origRow[d];\n                clearOneFromGate(r);\n                continue;\n            }\n\n            // 4) fallback: dispatch any remaining container\n            int any = -1;\n            for(int i=0;i<N;i++) for(int j=0;j<4;j++){\n                if(grid[i][j] != -1){ any = grid[i][j]; break; }\n            }\n            if(any != -1){\n                dispatchId(any);\n            } else {\n                step('.');\n            }\n        }\n\n        // If somehow not finished, continue brute-force dispatching until time limit.\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            int any = -1;\n            for(int i=0;i<N;i++) for(int j=0;j<4;j++){\n                if(grid[i][j] != -1){ any = grid[i][j]; break; }\n            }\n            if(any != -1) dispatchId(any);\n            else step('.');\n        }\n\n        // Ensure output length >= 1\n        if(turn == 0) step('.');\n    }\n\n    void print() const {\n        for(int i=0;i<N;i++){\n            cout << out[i] << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<vector<int>> A(n, vector<int>(n));\n    for(int i=0;i<n;i++){\n        for(int j=0;j<n;j++) cin >> A[i][j];\n    }\n\n    Solver solver(n, A);\n    solver.run();\n    solver.print();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF = (1LL<<62);\n\nstatic inline int id(int r, int c, int N){ return r*N + c; }\nstatic inline int r_of(int v, int N){ return v / N; }\nstatic inline int c_of(int v, int N){ return v % N; }\n\nstatic inline char move_dir(int from, int to, int N){\n    int fr = r_of(from, N), fc = c_of(from, N);\n    int tr = r_of(to, N), tc = c_of(to, N);\n    if (tr == fr-1 && tc == fc) return 'U';\n    if (tr == fr+1 && tc == fc) return 'D';\n    if (tr == fr && tc == fc-1) return 'L';\n    if (tr == fr && tc == fc+1) return 'R';\n    return '?';\n}\n\nstruct Emitter {\n    vector<string> ops;\n    void emit_move(char c) { ops.emplace_back(1, c); }\n    void emit_amount(char sign, long long d) {\n        while (d > 0) {\n            long long x = min(d, 1000000LL);\n            ops.push_back(string(1, sign) + to_string(x));\n            d -= x;\n        }\n    }\n};\n\nvector<vector<int>> build_children(const vector<int>& parent){\n    int V = (int)parent.size();\n    vector<vector<int>> ch(V);\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        if(p >= 0) ch[p].push_back(v);\n    }\n    return ch;\n}\n\nstruct TreeDP {\n    vector<long long> req;\n    vector<long long> gain;\n    vector<vector<int>> child_order;\n    long long root_borrow = 0; // not necessarily pre-borrowed; useful diagnostic\n};\n\n// DP heuristic: order children and compute minimal required entering load.\nTreeDP compute_tree_dp(const vector<vector<int>>& children, const vector<int>& h){\n    int V = (int)children.size();\n    TreeDP dp;\n    dp.req.assign(V, 0);\n    dp.gain.assign(V, 0);\n    dp.child_order.assign(V, {});\n\n    struct Task { long long req, gain; int child; };\n\n    function<void(int)> dfs = [&](int v){\n        for(int c: children[v]) dfs(c);\n\n        vector<Task> tasks;\n        tasks.reserve(children[v].size());\n        long long sum_children = 0;\n        for(int c: children[v]){\n            tasks.push_back(Task{dp.req[c], dp.gain[c], c});\n            sum_children += dp.gain[c];\n        }\n\n        auto cmp = [&](const Task& a, const Task& b){\n            bool ap = (a.gain >= 0);\n            bool bp = (b.gain >= 0);\n            if(ap && bp) return a.req < b.req;\n            if(ap != bp) return ap > bp;\n            // both negative gain: larger (req - gain) first\n            return (a.req - a.gain) > (b.req - b.gain);\n        };\n        sort(tasks.begin(), tasks.end(), cmp);\n\n        dp.child_order[v].clear();\n        for(auto &t: tasks) dp.child_order[v].push_back(t.child);\n\n        // child tasks feasibility\n        long long bal = 0, need = 0;\n        for(auto &t: tasks){\n            need = max(need, t.req - bal);\n            bal += t.gain;\n        }\n\n        long long hv = h[v];\n        long long e = max(0LL, hv);          // available supply if you choose to load it at v\n        long long exit_req = max(0LL, -hv);  // must be able to fill own negative eventually\n\n        if(v == 0){\n            long long borrow = max(0LL, need - e);\n            dp.root_borrow = borrow;\n            dp.req[v] = borrow;\n            dp.gain[v] = hv + sum_children;\n        }else{\n            long long r = 0;\n            r = max(r, need - e);\n            r = max(r, exit_req - e - sum_children);\n\n            long long g = hv + sum_children;\n            if(g < 0) r = max(r, -g);\n            r = max(r, 0LL);\n\n            dp.req[v] = r;\n            dp.gain[v] = g;\n        }\n    };\n\n    dfs(0);\n    return dp;\n}\n\n// Tree generators\nvector<int> bfs_tree(int N, const array<int,4>& ord){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0] = 1;\n    while(!q.empty()){\n        int v = q.front(); q.pop();\n        int r = r_of(v, N), c = c_of(v, N);\n        for(int t: ord){\n            int nr=r, nc=c;\n            if(t==0) nr--;\n            if(t==1) nr++;\n            if(t==2) nc--;\n            if(t==3) nc++;\n            if(nr<0||nr>=N||nc<0||nc>=N) continue;\n            int u = id(nr,nc,N);\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nvector<int> random_dfs_tree(int N, std::mt19937_64& rng){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    vector<int> st;\n    st.reserve(V);\n    st.push_back(0);\n    vis[0] = 1;\n\n    while(!st.empty()){\n        int v = st.back();\n        int r = r_of(v, N), c = c_of(v, N);\n\n        int cand[4]; int cc=0;\n        if(r>0){ int u=id(r-1,c,N); if(!vis[u]) cand[cc++]=u; }\n        if(r+1<N){ int u=id(r+1,c,N); if(!vis[u]) cand[cc++]=u; }\n        if(c>0){ int u=id(r,c-1,N); if(!vis[u]) cand[cc++]=u; }\n        if(c+1<N){ int u=id(r,c+1,N); if(!vis[u]) cand[cc++]=u; }\n\n        if(cc==0){\n            st.pop_back();\n        }else{\n            uniform_int_distribution<int> dist(0, cc-1);\n            int u = cand[dist(rng)];\n            vis[u]=1;\n            parent[u]=v;\n            st.push_back(u);\n        }\n    }\n    return parent;\n}\n\nvector<int> prim_biased_tree(int N, const vector<int>& h, std::mt19937_64& rng){\n    int V = N*N;\n    vector<int> parent(V, -2);\n    vector<char> in(V, 0);\n    vector<int> pos(V, -1);\n    vector<vector<int>> candP(V);\n\n    vector<int> frontier;\n    frontier.reserve(V);\n\n    auto add_front = [&](int u, int p){\n        if(in[u]) return;\n        if(pos[u] == -1){\n            pos[u] = (int)frontier.size();\n            frontier.push_back(u);\n        }\n        candP[u].push_back(p);\n    };\n    auto remove_front = [&](int u){\n        int i = pos[u];\n        if(i < 0) return;\n        int last = frontier.back();\n        frontier[i] = last;\n        pos[last] = i;\n        frontier.pop_back();\n        pos[u] = -1;\n    };\n\n    parent[0] = -1;\n    in[0] = 1;\n\n    auto try_neighbors = [&](int v){\n        int r = r_of(v,N), c=c_of(v,N);\n        if(r>0) add_front(id(r-1,c,N), v);\n        if(r+1<N) add_front(id(r+1,c,N), v);\n        if(c>0) add_front(id(r,c-1,N), v);\n        if(c+1<N) add_front(id(r,c+1,N), v);\n    };\n    try_neighbors(0);\n\n    int added = 1;\n    while(added < V){\n        int u = frontier[uniform_int_distribution<int>(0, (int)frontier.size()-1)(rng)];\n        // choose parent among candidates with mild opposite-sign bias\n        auto &ps = candP[u];\n        long long totw = 0;\n        vector<long long> w(ps.size(), 1);\n        for(size_t i=0;i<ps.size();i++){\n            int p = ps[i];\n            long long ww = 1;\n            if(h[u] != 0 && h[p] != 0 && (long long)h[u]*h[p] < 0) ww += 4; // prefer opposite\n            ww += (abs(h[u]) + abs(h[p]) >= 120 ? 1 : 0);\n            w[i] = ww;\n            totw += ww;\n        }\n        long long x = uniform_int_distribution<long long>(1, totw)(rng);\n        int psel = ps[0];\n        for(size_t i=0;i<ps.size();i++){\n            x -= w[i];\n            if(x <= 0){\n                psel = ps[i];\n                break;\n            }\n        }\n\n        parent[u] = psel;\n        in[u] = 1;\n        added++;\n\n        remove_front(u);\n        candP[u].clear(); candP[u].shrink_to_fit(); // small V; ok\n\n        try_neighbors(u);\n    }\n\n    // parent array is ready (root=0 has -1)\n    return parent;\n}\n\n// Improved evaluation with caching:\n// Before entering child c, enter with exactly req[c] load by dumping surplus at current node.\npair<long long, TreeDP> eval_tree_cached(const vector<int>& parent, const vector<int>& h, int N){\n    int V = N*N;\n    auto children = build_children(parent);\n    TreeDP dp = compute_tree_dp(children, h);\n\n    vector<long long> curH(V);\n    for(int i=0;i<V;i++) curH[i] = h[i];\n\n    long long load = 0;\n    long long cost = 0;\n\n    struct Frame{ int v; int idx; };\n    vector<Frame> st;\n    st.reserve(V);\n    st.push_back({0,0});\n    int cur = 0;\n\n    while(!st.empty()){\n        int v = st.back().v;\n        int &idx = st.back().idx;\n\n        if(idx < (int)dp.child_order[v].size()){\n            int c = dp.child_order[v][idx++];\n\n            // Ensure load >= req[c] by loading from current node if possible; if still lacking, borrow at root, else fail-safe borrow.\n            long long need = dp.req[c];\n            if(load < need){\n                long long take = min(need - load, max(0LL, curH[v]));\n                if(take > 0){\n                    cost += take;\n                    curH[v] -= take;\n                    load += take;\n                }\n                if(load < need){\n                    long long rem = need - load;\n                    // borrowing (ideally only happens at root)\n                    cost += rem;\n                    curH[v] -= rem;\n                    load += rem;\n                }\n            }\n            // Dump all surplus to enter child with exactly req[c]\n            if(load > need){\n                long long dump = load - need;\n                cost += dump;\n                curH[v] += dump;\n                load -= dump;\n            }\n\n            // Move v -> c\n            cost += 100 + load;\n            cur = c;\n            st.push_back({c,0});\n        }else{\n            // exit node v\n            if(v != 0){\n                // Fix v to height 0 by loading/removing surplus or unloading to fill deficit\n                if(curH[v] > 0){\n                    long long x = curH[v];\n                    cost += x;\n                    load += x;\n                    curH[v] = 0;\n                }else if(curH[v] < 0){\n                    long long x = -curH[v];\n                    if(load < x) return {INF, dp}; // should not happen\n                    cost += x;\n                    load -= x;\n                    curH[v] = 0;\n                }\n                int p = parent[v];\n                // Move v -> p\n                cost += 100 + load;\n                cur = p;\n            }\n            st.pop_back();\n        }\n    }\n\n    // At root: unload remaining load to root\n    if(load > 0){\n        cost += load;\n        curH[0] += load;\n        load = 0;\n    }\n    // If everything is consistent, curH[0] should now be 0 (conservation).\n    if(curH[0] != 0) return {INF, dp};\n\n    return {cost, dp};\n}\n\nvoid build_ops_tree_cached(const vector<int>& parent, const TreeDP& dp, const vector<int>& h, int N, vector<string>& out_ops){\n    int V = N*N;\n    vector<long long> curH(V);\n    for(int i=0;i<V;i++) curH[i] = h[i];\n\n    long long load = 0;\n    Emitter em;\n\n    struct Frame{ int v; int idx; };\n    vector<Frame> st;\n    st.reserve(V);\n    st.push_back({0,0});\n    int cur = 0;\n\n    while(!st.empty()){\n        int v = st.back().v;\n        int &idx = st.back().idx;\n\n        if(idx < (int)dp.child_order[v].size()){\n            int c = dp.child_order[v][idx++];\n\n            long long need = dp.req[c];\n            if(load < need){\n                long long take = min(need - load, max(0LL, curH[v]));\n                if(take > 0){\n                    em.emit_amount('+', take);\n                    curH[v] -= take;\n                    load += take;\n                }\n                if(load < need){\n                    long long rem = need - load;\n                    // borrow (normally only root)\n                    em.emit_amount('+', rem);\n                    curH[v] -= rem;\n                    load += rem;\n                }\n            }\n            if(load > need){\n                long long dump = load - need;\n                em.emit_amount('-', dump);\n                curH[v] += dump;\n                load -= dump;\n            }\n\n            em.emit_move(move_dir(v, c, N));\n            cur = c;\n            st.push_back({c,0});\n        }else{\n            if(v != 0){\n                if(curH[v] > 0){\n                    long long x = curH[v];\n                    em.emit_amount('+', x);\n                    load += x;\n                    curH[v] = 0;\n                }else if(curH[v] < 0){\n                    long long x = -curH[v];\n                    em.emit_amount('-', x);\n                    load -= x;\n                    curH[v] = 0;\n                }\n                int p = parent[v];\n                em.emit_move(move_dir(v, p, N));\n                cur = p;\n            }\n            st.pop_back();\n        }\n    }\n\n    if(load > 0){\n        em.emit_amount('-', load);\n        curH[0] += load;\n        load = 0;\n    }\n\n    out_ops = std::move(em.ops);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<int> h(N*N);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin >> h[id(i,j,N)];\n        }\n    }\n\n    // Candidate search over trees\n    long long best_cost = INF;\n    vector<int> best_parent;\n    TreeDP best_dp;\n\n    // deterministic BFS trees\n    {\n        array<array<int,4>,4> orders = {{\n            {3,1,2,0}, // R,D,L,U\n            {1,3,2,0}, // D,R,L,U\n            {3,2,1,0}, // R,L,D,U\n            {1,2,3,0}  // D,L,R,U\n        }};\n        for(auto ord: orders){\n            auto parent = bfs_tree(N, ord);\n            auto [cost, dp] = eval_tree_cached(parent, h, N);\n            if(cost < best_cost){\n                best_cost = cost;\n                best_parent = parent;\n                best_dp = std::move(dp);\n            }\n        }\n    }\n\n    mt19937_64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    auto t0 = chrono::steady_clock::now();\n\n    int it = 0;\n    while(true){\n        it++;\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n        if(sec > 1.80) break;\n\n        vector<int> parent;\n        if(it % 3 == 0) parent = prim_biased_tree(N, h, rng);\n        else parent = random_dfs_tree(N, rng);\n\n        auto [cost, dp] = eval_tree_cached(parent, h, N);\n        if(cost < best_cost){\n            best_cost = cost;\n            best_parent = parent;\n            best_dp = std::move(dp);\n        }\n    }\n\n    // Build ops for best\n    vector<string> ops;\n    build_ops_tree_cached(best_parent, best_dp, h, N, ops);\n\n    // safety (should be far below)\n    if((int)ops.size() > 100000){\n        ops.clear();\n    }\n\n    for(auto &s: ops) cout << s << \"\\n\";\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int INF_INT = 1e9;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ull;\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int n) { // [0,n)\n        return (int)(nextU64() % (uint64_t)n);\n    }\n};\n\nstruct Seed {\n    array<uint8_t, 15> x{};\n    int V = 0;\n    int peak = 0;\n};\n\nstatic inline int diffCount(const Seed& a, const Seed& b, int M) {\n    int d = 0;\n    for (int i = 0; i < M; i++) d += (a.x[i] != b.x[i]);\n    return d;\n}\n\nstatic inline int potentialSumMax(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += max<int>(a.x[i], b.x[i]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60\n\n    vector<Seed> seeds(SEED_COUNT);\n\n    auto readSeeds = [&]() {\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int sum = 0, pk = 0;\n            for (int l = 0; l < M; l++) {\n                int v;\n                cin >> v;\n                seeds[k].x[l] = (uint8_t)v;\n                sum += v;\n                pk = max(pk, v);\n            }\n            seeds[k].V = sum;\n            seeds[k].peak = pk;\n        }\n    };\n\n    readSeeds();\n\n    // Precompute grid neighbors and degrees.\n    const int P = N * N; // 36\n    vector<vector<int>> neigh(P);\n    vector<pair<int,int>> edges;\n    vector<int> degree(P, 0);\n    auto id = [&](int i, int j){ return i * N + j; };\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int v = id(i,j);\n            if (i > 0) neigh[v].push_back(id(i-1,j));\n            if (i + 1 < N) neigh[v].push_back(id(i+1,j));\n            if (j > 0) neigh[v].push_back(id(i,j-1));\n            if (j + 1 < N) neigh[v].push_back(id(i,j+1));\n            degree[v] = (int)neigh[v].size();\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j + 1 < N; j++) edges.push_back({id(i,j), id(i,j+1)});\n    }\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j < N; j++) edges.push_back({id(i,j), id(i+1,j)});\n    }\n\n    vector<int> posOrder(P);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b){\n        if (degree[a] != degree[b]) return degree[a] > degree[b];\n        return a < b;\n    });\n\n    RNG rng;\n    auto startTime = chrono::steady_clock::now();\n    const double TIME_LIMIT = 1.90; // safety vs 2.0\n\n    for (int t = 0; t < T; t++) {\n        // Time allocation for this turn\n        auto now = chrono::steady_clock::now();\n        double elapsed = chrono::duration<double>(now - startTime).count();\n        double remaining = max(0.0, TIME_LIMIT - elapsed);\n        double perTurn = remaining / max(1, (T - t));\n        auto turnStart = now;\n        auto turnEnd = turnStart + chrono::duration<double>(perTurn * 0.95);\n\n        // ---- 1) select 36 seeds ----\n        vector<int> idx(SEED_COUNT);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b){\n            if (seeds[a].V != seeds[b].V) return seeds[a].V > seeds[b].V;\n            return a < b;\n        });\n\n        const int eliteCount = 8;\n        vector<int> selected;\n        selected.reserve(P);\n        vector<char> used(SEED_COUNT, 0);\n        vector<char> protectedSeed(SEED_COUNT, 0);\n\n        auto addSeed = [&](int k, bool protect=false) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n            if (protect) protectedSeed[k] = 1;\n        };\n\n        // Elites\n        for (int i = 0; i < eliteCount; i++) addSeed(idx[i], true);\n\n        // Similar partner for each elite (preservation)\n        for (int i = 0; i < eliteCount; i++) {\n            int e = idx[i];\n            int best = -1;\n            int bestScore = INF_INT;\n            for (int j = 0; j < SEED_COUNT; j++) if (j != e) {\n                if (used[j]) continue;\n                int d = diffCount(seeds[e], seeds[j], M);\n                int vd = abs(seeds[e].V - seeds[j].V);\n                // prioritize similarity strongly, but avoid extremely low-value partner\n                int score = d * 100 + vd;\n                if (score < bestScore) {\n                    bestScore = score;\n                    best = j;\n                } else if (score == bestScore && seeds[j].V > seeds[best].V) {\n                    best = j;\n                }\n            }\n            if (best != -1) addSeed(best, true);\n        }\n\n        // Per-dimension top candidates\n        const int perDimTake = 2;\n        for (int l = 0; l < M; l++) {\n            vector<int> ord(SEED_COUNT);\n            iota(ord.begin(), ord.end(), 0);\n            nth_element(ord.begin(), ord.begin() + min(SEED_COUNT, 12), ord.end(), [&](int a, int b){\n                if (seeds[a].x[l] != seeds[b].x[l]) return seeds[a].x[l] > seeds[b].x[l];\n                return seeds[a].V > seeds[b].V;\n            });\n            // Just scan best few (cheap)\n            sort(ord.begin(), ord.begin() + min(SEED_COUNT, 12), [&](int a, int b){\n                if (seeds[a].x[l] != seeds[b].x[l]) return seeds[a].x[l] > seeds[b].x[l];\n                return seeds[a].V > seeds[b].V;\n            });\n            int taken = 0;\n            for (int z = 0; z < min(SEED_COUNT, 12) && taken < perDimTake; z++) {\n                int k = ord[z];\n                if (!used[k]) {\n                    addSeed(k, false);\n                    taken++;\n                }\n            }\n        }\n\n        // Fill remaining by mixed score\n        auto mixedScore = [&](int k) -> double {\n            return (double)seeds[k].V + 0.8 * (double)seeds[k].peak;\n        };\n        vector<int> rest;\n        rest.reserve(SEED_COUNT);\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        sort(rest.begin(), rest.end(), [&](int a, int b){\n            double sa = mixedScore(a), sb = mixedScore(b);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n        for (int k : rest) {\n            if ((int)selected.size() >= P) break;\n            addSeed(k, false);\n        }\n\n        // If too many (can happen due to per-dimension), prune non-protected\n        if ((int)selected.size() > P) {\n            auto importance = [&](int k) -> double {\n                return (double)seeds[k].V + 0.3 * (double)seeds[k].peak;\n            };\n            // collect removable\n            vector<int> removable;\n            for (int k : selected) if (!protectedSeed[k]) removable.push_back(k);\n            sort(removable.begin(), removable.end(), [&](int a, int b){\n                double ia = importance(a), ib = importance(b);\n                if (ia != ib) return ia < ib; // remove low importance first\n                return a > b;\n            });\n            int ptr = 0;\n            while ((int)selected.size() > P && ptr < (int)removable.size()) {\n                int rm = removable[ptr++];\n                // remove rm from selected\n                auto it = find(selected.begin(), selected.end(), rm);\n                if (it != selected.end()) selected.erase(it);\n            }\n            // If still too many (unlikely), drop from end\n            while ((int)selected.size() > P) selected.pop_back();\n        }\n\n        // ---- 2) placement via SA ----\n\n        // Local indexing for selected seeds\n        vector<int> globOfLocal(P);\n        for (int i = 0; i < P; i++) globOfLocal[i] = selected[i];\n\n        // Pair score matrix among selected (local indices)\n        double phase = (T == 1) ? 1.0 : (double)t / (double)(T - 1); // 0..1\n        double lambda = 2.0 + 3.0 * phase; // similarity penalty increases over time\n        double rho    = 0.05 + 0.45 * phase; // robustness term increases over time\n\n        vector<vector<double>> pairScore(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            pairScore[i][i] = 0.0;\n            for (int j = i + 1; j < P; j++) {\n                const Seed& A = seeds[globOfLocal[i]];\n                const Seed& B = seeds[globOfLocal[j]];\n                int pot = potentialSumMax(A, B, M);\n                int d = diffCount(A, B, M);\n                int mn = min(A.V, B.V);\n                double s = (double)pot + rho * (double)mn - lambda * (double)d;\n                pairScore[i][j] = pairScore[j][i] = s;\n            }\n        }\n\n        // Initial permutation: high-importance seeds to high-degree positions\n        vector<int> localOrder(P);\n        iota(localOrder.begin(), localOrder.end(), 0);\n        sort(localOrder.begin(), localOrder.end(), [&](int a, int b){\n            int ga = globOfLocal[a], gb = globOfLocal[b];\n            double sa = (double)seeds[ga].V + 0.5 * (double)seeds[ga].peak;\n            double sb = (double)seeds[gb].V + 0.5 * (double)seeds[gb].peak;\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        vector<int> perm(P, 0); // perm[pos] = local seed index\n        for (int k = 0; k < P; k++) {\n            perm[posOrder[k]] = localOrder[k];\n        }\n\n        auto evalObjective = [&]() -> double {\n            double s = 0.0;\n            for (auto [u, v] : edges) {\n                s += pairScore[perm[u]][perm[v]];\n            }\n            return s;\n        };\n\n        double cur = evalObjective();\n        double best = cur;\n        vector<int> bestPerm = perm;\n\n        // SA parameters\n        const double tempStart = 500.0;\n        const double tempEnd = 10.0;\n\n        auto getTemp = [&](double prog) -> double {\n            // geometric cooling\n            double r = tempEnd / tempStart;\n            return tempStart * pow(r, prog);\n        };\n\n        while (chrono::steady_clock::now() < turnEnd) {\n            int a = rng.nextInt(P);\n            int b = rng.nextInt(P);\n            if (a == b) continue;\n\n            int la = perm[a];\n            int lb = perm[b];\n            double delta = 0.0;\n\n            for (int na : neigh[a]) {\n                if (na == b) continue;\n                int lx = perm[na];\n                delta -= pairScore[la][lx];\n                delta += pairScore[lb][lx];\n            }\n            for (int nb : neigh[b]) {\n                if (nb == a) continue;\n                int lx = perm[nb];\n                delta -= pairScore[lb][lx];\n                delta += pairScore[la][lx];\n            }\n\n            auto now2 = chrono::steady_clock::now();\n            double prog = chrono::duration<double>(now2 - turnStart).count() /\n                          max(1e-9, chrono::duration<double>(turnEnd - turnStart).count());\n            prog = min(1.0, max(0.0, prog));\n            double temp = getTemp(prog);\n\n            bool accept = false;\n            if (delta >= 0) {\n                accept = true;\n            } else {\n                double p = exp(delta / temp);\n                if (rng.nextDouble() < p) accept = true;\n            }\n\n            if (accept) {\n                swap(perm[a], perm[b]);\n                cur += delta;\n                if (cur > best) {\n                    best = cur;\n                    bestPerm = perm;\n                }\n            }\n        }\n\n        perm = bestPerm;\n\n        // ---- Output layout ----\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = id(i,j);\n                int localIdx = perm[pos];\n                int globalIdx = globOfLocal[localIdx];\n                if (j) cout << ' ';\n                cout << globalIdx;\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        // ---- Read next generation ----\n        readSeeds();\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int x, y;\n};\n\nstatic const int dx4[4] = {0, 1, 0, -1}; // R, D, L, U\nstatic const int dy4[4] = {1, 0, -1, 0};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    vector<vector<int>> cur(N, vector<int>(N, 0));\n    vector<vector<int>> target(N, vector<int>(N, 0));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cur[i][j] = (s[i][j] == '1');\n            target[i][j] = (t[i][j] == '1');\n        }\n    }\n\n    // Build surplus and deficit lists.\n    vector<Pos> surplus, deficit;\n    surplus.reserve(N*N);\n    deficit.reserve(N*N);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (cur[i][j] == 1 && target[i][j] == 0) surplus.push_back({i,j});\n        if (cur[i][j] == 0 && target[i][j] == 1) deficit.push_back({i,j});\n    }\n\n    // Design: V'=2, edge (0->1) length 1, root initial position (0,0).\n    const int Vp = 2;\n\n    // State\n    int rx = 0, ry = 0; // root\n    int dir = 0;        // 0:R 1:D 2:L 3:U ; initial edges extend to the right => R\n    bool holding = false;\n\n    vector<string> ops;\n    ops.reserve(100000);\n\n    auto inside = [&](int x, int y) -> bool {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    };\n\n    auto rotStep = [&](int curDir, int toDir) -> char {\n        int cw = (toDir - curDir + 4) % 4;\n        int ccw = (curDir - toDir + 4) % 4;\n        if (cw <= ccw) return 'R';\n        else return 'L';\n    };\n\n    auto applyTurn = [&](char mv, char rot, bool wantP) {\n        // decide actual action legality after move/rot\n        // Build command string of length 2*Vp = 4:\n        // [0]=move, [1]=rot of vertex1, [2]=action of v0, [3]=action of v1\n        string cmd(2 * Vp, '.');\n        cmd[0] = mv;\n        cmd[1] = rot;\n        cmd[2] = '.';\n\n        // Apply movement (root must remain inside)\n        int nrx = rx, nry = ry;\n        if (mv == 'U') nrx--;\n        else if (mv == 'D') nrx++;\n        else if (mv == 'L') nry--;\n        else if (mv == 'R') nry++;\n\n        if (mv != '.') {\n            if (inside(nrx, nry)) {\n                rx = nrx; ry = nry;\n            } else {\n                // should not happen with our planning; output '.' instead\n                cmd[0] = '.';\n            }\n        }\n\n        // Apply rotation\n        if (rot == 'L') dir = (dir + 3) % 4;\n        else if (rot == 'R') dir = (dir + 1) % 4;\n        else cmd[1] = '.';\n\n        // Action after move/rot\n        char actChar = '.';\n        int gx = rx + dx4[dir];\n        int gy = ry + dy4[dir];\n        if (wantP && inside(gx, gy)) {\n            if (!holding) {\n                // pick only if cell has takoyaki and it's not a target cell (we avoid harming correct ones)\n                if (cur[gx][gy] == 1 && target[gx][gy] == 0) {\n                    cur[gx][gy] = 0;\n                    holding = true;\n                    actChar = 'P';\n                }\n            } else {\n                // place only if empty and it's a target cell\n                if (cur[gx][gy] == 0 && target[gx][gy] == 1) {\n                    cur[gx][gy] = 1;\n                    holding = false;\n                    actChar = 'P';\n                }\n            }\n        }\n        cmd[3] = actChar;\n\n        ops.push_back(std::move(cmd));\n    };\n\n    // Move root to (tx,ty) and orient dir to tdir, using Manhattan path;\n    // rotate simultaneously during moves when possible.\n    auto moveRootAndOrient = [&](int tx, int ty, int tdir, bool doActionAtEnd) {\n        vector<pair<char,char>> steps;\n\n        int cx = rx, cy = ry;\n        int cdir = dir;\n\n        auto pushStep = [&](char mv) {\n            char rot = '.';\n            if (cdir != tdir) {\n                rot = rotStep(cdir, tdir);\n                if (rot == 'L') cdir = (cdir + 3) % 4;\n                else if (rot == 'R') cdir = (cdir + 1) % 4;\n            }\n            // update root pos in local simulation\n            if (mv == 'U') cx--;\n            else if (mv == 'D') cx++;\n            else if (mv == 'L') cy--;\n            else if (mv == 'R') cy++;\n            steps.push_back({mv, rot});\n        };\n\n        // Horizontal then vertical (any fixed order is fine)\n        while (cy < ty) pushStep('R');\n        while (cy > ty) pushStep('L');\n        while (cx < tx) pushStep('D');\n        while (cx > tx) pushStep('U');\n\n        // Remaining rotations\n        while (cdir != tdir) {\n            char rot = rotStep(cdir, tdir);\n            if (rot == 'L') cdir = (cdir + 3) % 4;\n            else cdir = (cdir + 1) % 4;\n            steps.push_back({'.', rot});\n        }\n\n        if (doActionAtEnd) {\n            if (steps.empty()) steps.push_back({'.','.'});\n            for (int i = 0; i < (int)steps.size(); i++) {\n                bool wantP = (i + 1 == (int)steps.size());\n                applyTurn(steps[i].first, steps[i].second, wantP);\n            }\n        } else {\n            for (auto [mv, rot] : steps) applyTurn(mv, rot, false);\n        }\n    };\n\n    // Make fingertip land on cell (x,y), optionally do pick/place there at the end.\n    auto goFingerToCell = [&](int x, int y, bool doActionAtEnd) {\n        // Candidate (root position, dir) such that root + dir == (x,y)\n        int bestTurns = INT_MAX;\n        int bestRx = rx, bestRy = ry, bestDir = dir;\n\n        for (int d = 0; d < 4; d++) {\n            int rrx = x - dx4[d];\n            int rry = y - dy4[d];\n            if (!inside(rrx, rry)) continue;\n\n            int dist = abs(rx - rrx) + abs(ry - rry);\n            int cw = (d - dir + 4) % 4;\n            int ccw = (dir - d + 4) % 4;\n            int rotCost = min(cw, ccw);\n            int turns = max(dist, rotCost); // rotation can be overlapped with movement\n            // tie-breakers: smaller dist, smaller rotCost\n            if (turns < bestTurns ||\n                (turns == bestTurns && dist < abs(rx - bestRx) + abs(ry - bestRy)) ||\n                (turns == bestTurns && dist == abs(rx - bestRx) + abs(ry - bestRy) && rotCost < min((bestDir-dir+4)%4,(dir-bestDir+4)%4))) {\n                bestTurns = turns;\n                bestRx = rrx;\n                bestRy = rry;\n                bestDir = d;\n            }\n        }\n\n        // Move and orient\n        moveRootAndOrient(bestRx, bestRy, bestDir, doActionAtEnd);\n    };\n\n    // Main greedy transport loop\n    while (!deficit.empty() && !surplus.empty() && (int)ops.size() < 100000) {\n        // Choose closest pair\n        int bi = -1, bj = -1;\n        int best = INT_MAX;\n        for (int i = 0; i < (int)surplus.size(); i++) {\n            for (int j = 0; j < (int)deficit.size(); j++) {\n                int d = abs(surplus[i].x - deficit[j].x) + abs(surplus[i].y - deficit[j].y);\n                if (d < best) {\n                    best = d;\n                    bi = i; bj = j;\n                }\n            }\n        }\n        if (bi < 0) break;\n\n        Pos src = surplus[bi];\n        Pos dst = deficit[bj];\n\n        // Go pick at src\n        goFingerToCell(src.x, src.y, true);\n        if (!holding) {\n            // If something went wrong (shouldn't), skip this source by removing it to avoid infinite loop\n            surplus[bi] = surplus.back();\n            surplus.pop_back();\n            continue;\n        }\n\n        // Go drop at dst\n        goFingerToCell(dst.x, dst.y, true);\n        if (holding) {\n            // failed to drop (shouldn't), stop to keep output legal and bounded\n            break;\n        }\n\n        // Update lists: remove used src and dst\n        surplus[bi] = surplus.back();\n        surplus.pop_back();\n        deficit[bj] = deficit.back();\n        deficit.pop_back();\n    }\n\n    // Output arm design\n    cout << Vp << \"\\n\";\n    cout << 0 << \" \" << 1 << \"\\n\";\n    cout << 0 << \" \" << 0 << \"\\n\"; // initial root position\n\n    // Output operations\n    for (auto &cmd : ops) cout << cmd << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXC = 100000;\nstatic constexpr int MAXC1 = 100001; // MAXC + 1\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed = 0) {\n        if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Pt {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Rect {\n    int x1, x2, y1, y2; // inclusive bounds, require x1 < x2, y1 < y2\n};\n\nstatic inline int binCoord(int v, int G) {\n    // v in [0..100000], map to [0..G-1]\n    // Using MAXC1=100001 so that 100000 maps to G-1.\n    long long b = (long long)v * G / MAXC1;\n    if (b < 0) b = 0;\n    if (b >= G) b = G - 1;\n    return (int)b;\n}\n\nstatic inline long long perimeter2(const Rect& r) {\n    // actual perimeter = 2*(dx+dy)\n    long long dx = r.x2 - r.x1;\n    long long dy = r.y2 - r.y1;\n    return 2LL * (dx + dy);\n}\n\nstatic int evalDiff(const vector<Pt>& pts, const Rect& r) {\n    int s = 0;\n    for (const auto &p : pts) {\n        if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) s += p.w;\n    }\n    return s;\n}\n\nstatic bool containsAny(const vector<Pt>& pts, const Rect& r) {\n    for (const auto &p : pts) {\n        if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N; // fixed 5000 in all tests\n    vector<Pt> pts;\n    pts.reserve(2 * N);\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n        int w = (i < N ? +1 : -1);\n        pts.push_back({x, y, w});\n    }\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    // --- 1) Coarse grid max-sum subrectangle ---\n    const int G = 200;\n    vector<int> bx(G + 1), by(G + 1);\n    for (int i = 0; i <= G; i++) {\n        bx[i] = (int)((long long)i * MAXC1 / G);\n        by[i] = (int)((long long)i * MAXC1 / G);\n    }\n    // bx[G]=by[G]=100001\n\n    vector<vector<int>> grid(G, vector<int>(G, 0));\n    for (auto &p : pts) {\n        int gx = binCoord(p.x, G);\n        int gy = binCoord(p.y, G);\n        grid[gy][gx] += p.w;\n    }\n\n    int bestSum = INT_MIN;\n    int bestL = 0, bestR = 0, bestB = 0, bestT = 0;\n\n    vector<int> colSum(G);\n    for (int L = 0; L < G; L++) {\n        fill(colSum.begin(), colSum.end(), 0);\n        for (int R = L; R < G; R++) {\n            for (int y = 0; y < G; y++) colSum[y] += grid[y][R];\n\n            // Kadane on colSum\n            int cur = 0;\n            int curStart = 0;\n            int localBest = INT_MIN;\n            int localB = 0, localT = 0;\n\n            for (int y = 0; y < G; y++) {\n                if (cur <= 0) {\n                    cur = colSum[y];\n                    curStart = y;\n                } else {\n                    cur += colSum[y];\n                }\n                if (cur > localBest) {\n                    localBest = cur;\n                    localB = curStart;\n                    localT = y;\n                }\n            }\n\n            if (localBest > bestSum) {\n                bestSum = localBest;\n                bestL = L; bestR = R;\n                bestB = localB; bestT = localT;\n            }\n        }\n    }\n\n    auto rectFromGrid = [&](int L, int R, int B, int T) -> Rect {\n        int x1 = bx[L];\n        int x2 = bx[R + 1] - 1;\n        int y1 = by[B];\n        int y2 = by[T + 1] - 1;\n        x1 = max(0, min(MAXC, x1));\n        x2 = max(0, min(MAXC, x2));\n        y1 = max(0, min(MAXC, y1));\n        y2 = max(0, min(MAXC, y2));\n        if (x2 <= x1) x2 = min(MAXC, x1 + 1);\n        if (y2 <= y1) y2 = min(MAXC, y1 + 1);\n        return Rect{x1, x2, y1, y2};\n    };\n\n    Rect curR = rectFromGrid(bestL, bestR, bestB, bestT);\n    int curDiff = evalDiff(pts, curR);\n\n    Rect bestRct = curR;\n    int bestDiff = curDiff;\n\n    // --- 2) Some random rectangle sampling (cheap multi-start boost) ---\n    auto clampi = [&](int v) { return max(0, min(MAXC, v)); };\n    auto tryUpdate = [&](const Rect& r) {\n        if (!(r.x1 < r.x2 && r.y1 < r.y2)) return;\n        if (perimeter2(r) > 400000) return;\n        int d = evalDiff(pts, r);\n        if (d > bestDiff) {\n            bestDiff = d;\n            bestRct = r;\n        }\n    };\n\n    // Random rectangles centered around random points (tends to hit clusters)\n    for (int it = 0; it < 200; it++) {\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size() - 1)];\n        int wx = rng.nextInt(200, 20000);\n        int wy = rng.nextInt(200, 20000);\n        int x1 = clampi(p.x - wx);\n        int x2 = clampi(p.x + wx);\n        int y1 = clampi(p.y - wy);\n        int y2 = clampi(p.y + wy);\n        if (x2 <= x1) x2 = min(MAXC, x1 + 1);\n        if (y2 <= y1) y2 = min(MAXC, y1 + 1);\n        tryUpdate(Rect{x1, x2, y1, y2});\n    }\n\n    // start SA from current best\n    curR = bestRct;\n    curDiff = bestDiff;\n\n    // --- 3) Candidate coordinate lists for SA refinement ---\n    vector<int> candX, candY;\n    candX.reserve(2000);\n    candY.reserve(2000);\n    auto addCand = [&](vector<int>& v, int c) {\n        if (0 <= c && c <= MAXC) v.push_back(c);\n    };\n\n    addCand(candX, 0); addCand(candX, MAXC);\n    addCand(candY, 0); addCand(candY, MAXC);\n\n    // Add point-based candidates (x, x\u00b11), random sample\n    int samples = 600;\n    for (int i = 0; i < samples; i++) {\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size() - 1)];\n        addCand(candX, p.x); addCand(candX, p.x - 1); addCand(candX, p.x + 1);\n        addCand(candY, p.y); addCand(candY, p.y - 1); addCand(candY, p.y + 1);\n    }\n    // Also add current boundaries and neighbors\n    for (int d = -3; d <= 3; d++) {\n        addCand(candX, curR.x1 + d);\n        addCand(candX, curR.x2 + d);\n        addCand(candY, curR.y1 + d);\n        addCand(candY, curR.y2 + d);\n    }\n\n    sort(candX.begin(), candX.end());\n    candX.erase(unique(candX.begin(), candX.end()), candX.end());\n    sort(candY.begin(), candY.end());\n    candY.erase(unique(candY.begin(), candY.end()), candY.end());\n\n    // --- 4) Simulated annealing on rectangle sides ---\n    auto startTime = chrono::high_resolution_clock::now();\n    const double TIME_LIMIT = 1.85; // seconds (keep margin)\n    const double T0 = 30.0;\n    const double T1 = 0.5;\n\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - startTime).count();\n    };\n\n    int iters = 0;\n    while (true) {\n        double t = elapsedSec();\n        if (t > TIME_LIMIT) break;\n        double prog = t / TIME_LIMIT;\n        double T = T0 * pow(T1 / T0, prog);\n\n        Rect nxt = curR;\n        int side = rng.nextInt(0, 3); // 0:L 1:R 2:B 3:T\n\n        if (side == 0) { // left\n            int nx1 = candX[rng.nextInt(0, (int)candX.size() - 1)];\n            if (nx1 >= nxt.x2) { iters++; continue; }\n            nxt.x1 = nx1;\n        } else if (side == 1) { // right\n            int nx2 = candX[rng.nextInt(0, (int)candX.size() - 1)];\n            if (nx2 <= nxt.x1) { iters++; continue; }\n            nxt.x2 = nx2;\n        } else if (side == 2) { // bottom\n            int ny1 = candY[rng.nextInt(0, (int)candY.size() - 1)];\n            if (ny1 >= nxt.y2) { iters++; continue; }\n            nxt.y1 = ny1;\n        } else { // top\n            int ny2 = candY[rng.nextInt(0, (int)candY.size() - 1)];\n            if (ny2 <= nxt.y1) { iters++; continue; }\n            nxt.y2 = ny2;\n        }\n\n        if (perimeter2(nxt) > 400000) { iters++; continue; }\n\n        int nd = evalDiff(pts, nxt);\n        int delta = nd - curDiff;\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curR = nxt;\n            curDiff = nd;\n            if (curDiff > bestDiff) {\n                bestDiff = curDiff;\n                bestRct = curR;\n            }\n        }\n        iters++;\n    }\n\n    // If somehow bestDiff < 0, output an empty small rectangle (diff=0 => score 1)\n    if (bestDiff < 0) {\n        Rect empty{0, 1, 0, 1};\n        for (int tries = 0; tries < 2000; tries++) {\n            int x1 = rng.nextInt(0, MAXC - 1);\n            int y1 = rng.nextInt(0, MAXC - 1);\n            Rect r{x1, x1 + 1, y1, y1 + 1};\n            if (!containsAny(pts, r)) { empty = r; break; }\n        }\n        bestRct = empty;\n        bestDiff = 0;\n    }\n\n    // Final sanity\n    if (!(bestRct.x1 < bestRct.x2 && bestRct.y1 < bestRct.y2)) {\n        // fallback\n        bestRct = Rect{0, 1, 0, 1};\n    }\n    if (perimeter2(bestRct) > 400000) {\n        // should not happen, but clamp as fallback\n        bestRct = Rect{0, 100000, 0, 100000};\n    }\n\n    // Output rectangle as orthogonal simple polygon (4 vertices), all distinct.\n    cout << 4 << \"\\n\";\n    cout << bestRct.x1 << \" \" << bestRct.y1 << \"\\n\";\n    cout << bestRct.x2 << \" \" << bestRct.y1 << \"\\n\";\n    cout << bestRct.x2 << \" \" << bestRct.y2 << \"\\n\";\n    cout << bestRct.x1 << \" \" << bestRct.y2 << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Plan {\n    vector<Op> ops;\n    long long predW = (1LL<<62);\n    long long predH = (1LL<<62);\n    long long predScore = (1LL<<62);\n    string tag;\n};\n\nstatic inline pair<long long,long long> dims(const vector<long long>& w, const vector<long long>& h, int i, int r){\n    if(r==0) return {w[i], h[i]};\n    return {h[i], w[i]};\n}\n\nstatic inline int rot_wide_minheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=max(w,h) and height=min(w,h)\n    return (w[i] < h[i]) ? 1 : 0;\n}\nstatic inline int rot_narrow_maxheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=min(w,h) and height=max(w,h)\n    return (w[i] > h[i]) ? 1 : 0;\n}\n\nPlan make_single_row(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r = (rotMode==0 ? rot_wide_minheight(w,h,i) : rot_narrow_maxheight(w,h,i));\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'L',-1});\n        W += ww;\n        H = max(H, hh);\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_row_wide\" : \"single_row_narrow\");\n    return pl;\n}\n\nPlan make_single_col(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r;\n        if(rotMode==0){\n            // minimize width\n            r = (w[i] > h[i]) ? 1 : 0;\n        }else{\n            // minimize height (often worse for columns but add diversity)\n            r = (w[i] < h[i]) ? 1 : 0;\n        }\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'U',-1});\n        W = max(W, ww);\n        H += hh;\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_col_minW\" : \"single_col_minH\");\n    return pl;\n}\n\n// Contiguous shelf rows with width limit M (simple fallback/diversity).\nPlan make_shelf_rows_width_limit(const vector<long long>& w, const vector<long long>& h, long long M){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n\n    long long totalH = 0;\n    long long maxW = 0;\n\n    int prevRowRep = -1;\n    long long curW = 0;\n    long long curH = 0;\n    int curRep = -1;\n\n    auto close_row = [&](){\n        if(curRep==-1) return;\n        totalH += curH;\n        maxW = max(maxW, curW);\n        prevRowRep = curRep;\n        curW = 0;\n        curH = 0;\n        curRep = -1;\n    };\n\n    for(int i=0;i<N;i++){\n        // try both rotations\n        auto [w0,h0] = dims(w,h,i,0);\n        auto [w1,h1] = dims(w,h,i,1);\n        bool fit0 = (curRep==-1 ? (w0<=M || curW==0) : (curW + w0 <= M));\n        bool fit1 = (curRep==-1 ? (w1<=M || curW==0) : (curW + w1 <= M));\n\n        int r = -1;\n        if(curRep==-1){\n            // new row: choose smaller height\n            if(h0 < h1) r=0; else r=1;\n        }else{\n            if(fit0 && fit1){\n                // choose smaller resulting row height, tie by smaller width\n                long long nh0 = max(curH, h0), nh1 = max(curH, h1);\n                if(nh0 != nh1) r = (nh0 < nh1 ? 0 : 1);\n                else r = (w0 < w1 ? 0 : 1);\n            }else if(fit0) r=0;\n            else if(fit1) r=1;\n        }\n\n        if(curRep!=-1 && r==-1){\n            close_row();\n            // new row, pick smaller height\n            if(h0 < h1) r=0; else r=1;\n        }\n\n        auto [ww,hh] = dims(w,h,i,r);\n        int b = (prevRowRep==-1 ? -1 : prevRowRep);\n        pl.ops.push_back({i,r,'L',b});\n        curW += ww;\n        if(hh > curH){\n            curH = hh;\n            curRep = i;\n        }else if(curRep==-1){\n            curRep = i;\n        }\n    }\n    close_row();\n\n    pl.predW = maxW;\n    pl.predH = totalH;\n    pl.predScore = pl.predW + pl.predH;\n    pl.tag = \"shelf_rows_M=\" + to_string(M);\n    return pl;\n}\n\n// Fixed prefix headers 0..m-1 in top row, then greedy assign remaining to columns.\n// Requires each assigned rectangle width <= its column width, otherwise infeasible.\nPlan make_prefix_columns_bruteforce(const vector<long long>& w, const vector<long long>& h, int m){\n    int N = (int)w.size();\n    Plan best;\n    best.predScore = (1LL<<62);\n    if(m<=0 || m> N) return best;\n\n    int lim = 1<<m;\n    vector<int> bestHeaderRot(m,0);\n    vector<int> bestCol(N,-1), bestRot(N,0);\n\n    for(int mask=0; mask<lim; mask++){\n        vector<long long> colW(m), colH(m);\n        long long totalW = 0;\n        long long maxH = 0;\n        for(int j=0;j<m;j++){\n            int r = (mask>>j)&1;\n            auto [ww,hh] = dims(w,h,j,r);\n            colW[j]=ww; colH[j]=hh;\n            totalW += ww;\n            maxH = max(maxH, hh);\n        }\n\n        vector<int> colOf(N,-1), rotOf(N,0);\n        for(int j=0;j<m;j++){\n            colOf[j]=j;\n            rotOf[j]= (mask>>j)&1;\n        }\n\n        bool ok = true;\n        for(int i=m;i<N;i++){\n            long long bestObj = (1LL<<62);\n            int bestJ=-1, bestR=0;\n            for(int j=0;j<m;j++){\n                for(int r=0;r<=1;r++){\n                    auto [ww,hh] = dims(w,h,i,r);\n                    if(ww > colW[j]) continue;\n                    long long nh = colH[j] + hh;\n                    long long nMaxH = max(maxH, nh);\n                    long long obj = totalW + nMaxH;\n                    if(obj < bestObj || (obj==bestObj && nh < colH[bestJ] + dims(w,h,i,bestR).second)){\n                        bestObj=obj;\n                        bestJ=j; bestR=r;\n                    }\n                }\n            }\n            if(bestJ==-1){\n                ok=false; break;\n            }\n            auto [ww,hh] = dims(w,h,i,bestR);\n            colH[bestJ] += hh;\n            maxH = max(maxH, colH[bestJ]);\n            colOf[i]=bestJ;\n            rotOf[i]=bestR;\n        }\n        if(!ok) continue;\n\n        long long score = totalW + maxH;\n        if(score < best.predScore){\n            best.predScore = score;\n            best.predW = totalW;\n            best.predH = maxH;\n            best.ops.clear();\n            best.ops.reserve(N);\n\n            // build operations: headers L, others U with b = header of left column\n            // column j starts at right edge of header (j-1) (or x=0 if j=0)\n            for(int i=0;i<N;i++){\n                int r = rotOf[i];\n                if(i < m){\n                    best.ops.push_back({i,r,'L',-1});\n                }else{\n                    int cj = colOf[i];\n                    int b = (cj==0 ? -1 : (cj-1)); // header index (cj-1) because headers are 0..m-1\n                    best.ops.push_back({i,r,'U',b});\n                }\n            }\n            best.tag = \"prefix_cols_bruteforce_m=\" + to_string(m);\n        }\n    }\n    return best;\n}\n\n// Online columns: open new columns as needed/beneficial. Columns are disjoint by enforcing width<=colWidth.\nPlan make_online_columns(const vector<long long>& w, const vector<long long>& h,\n                         long long openBias, int headerMode, std::mt19937_64* rng = nullptr)\n{\n    int N = (int)w.size();\n    struct Col{ long long W,H; int headerIdx; };\n    vector<Col> cols;\n    vector<Op> ops;\n    ops.reserve(N);\n\n    long long totalW = 0;\n    long long maxH = 0;\n\n    auto chooseHeaderRot = [&](int i)->int{\n        if(headerMode==0) return rot_wide_minheight(w,h,i);\n        else return rot_narrow_maxheight(w,h,i);\n    };\n\n    for(int i=0;i<N;i++){\n        if(cols.empty()){\n            int r = chooseHeaderRot(i);\n            auto [ww,hh] = dims(w,h,i,r);\n            cols.push_back({ww,hh,i});\n            totalW += ww;\n            maxH = max(maxH, hh);\n            ops.push_back({i,r,'L',-1});\n            continue;\n        }\n\n        // best existing placement\n        long long bestObj = (1LL<<62);\n        int bestC = -1, bestR = 0;\n        for(int c=0;c<(int)cols.size();c++){\n            for(int r=0;r<=1;r++){\n                auto [ww,hh] = dims(w,h,i,r);\n                if(ww > cols[c].W) continue;\n                long long nh = cols[c].H + hh;\n                long long nMaxH = max(maxH, nh);\n                long long obj = totalW + nMaxH;\n                if(obj < bestObj){\n                    bestObj = obj;\n                    bestC = c;\n                    bestR = r;\n                }else if(obj == bestObj && rng){\n                    // random tie-break to diversify\n                    if(((*rng)() & 7ULL)==0ULL){\n                        bestC = c;\n                        bestR = r;\n                    }\n                }\n            }\n        }\n\n        // open new column option (always feasible)\n        int hr = chooseHeaderRot(i);\n        auto [wNew,hNew] = dims(w,h,i,hr);\n        long long openObj = (totalW + wNew) + max(maxH, hNew) + openBias;\n\n        bool doOpen = false;\n        if(bestC==-1) doOpen = true;\n        else if(openObj < bestObj) doOpen = true;\n\n        if(doOpen){\n            cols.push_back({wNew,hNew,i});\n            totalW += wNew;\n            maxH = max(maxH, hNew);\n            ops.push_back({i,hr,'L',-1});\n        }else{\n            auto [ww,hh] = dims(w,h,i,bestR);\n            cols[bestC].H += hh;\n            maxH = max(maxH, cols[bestC].H);\n            int b = (bestC==0 ? -1 : cols[bestC-1].headerIdx);\n            ops.push_back({i,bestR,'U',b});\n        }\n    }\n\n    Plan pl;\n    pl.ops = std::move(ops);\n    pl.predW = totalW;\n    pl.predH = maxH;\n    pl.predScore = totalW + maxH;\n    pl.tag = string(\"online_cols_bias=\") + to_string(openBias) + (headerMode==0 ? \"_wide\" : \"_narrow\");\n    return pl;\n}\n\nstatic uint64_t hash_plan_ops(const vector<Op>& ops){\n    // lightweight hash to drop exact duplicates\n    uint64_t x = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v){\n        x ^= v;\n        x *= 1099511628211ULL;\n    };\n    for(const auto& op: ops){\n        mix((uint64_t)op.p);\n        mix((uint64_t)op.r);\n        mix((uint64_t)op.d);\n        mix((uint64_t)(op.b + 2)); // shift\n    }\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    cin >> N >> T >> sigma;\n    vector<long long> w(N), h(N);\n    for(int i=0;i<N;i++) cin >> w[i] >> h[i];\n\n    mt19937_64 rng(123456789ULL);\n\n    vector<Plan> plans;\n\n    // Baselines\n    plans.push_back(make_single_row(w,h,0));\n    plans.push_back(make_single_row(w,h,1));\n    plans.push_back(make_single_col(w,h,0));\n    plans.push_back(make_single_col(w,h,1));\n\n    // Shelf row variants (contiguous), based on area scale\n    long double area = 0;\n    for(int i=0;i<N;i++) area += (long double)w[i] * (long double)h[i];\n    long long base = (long long) llround(sqrt((long double)max((long double)1.0, area)));\n    vector<long long> factors = {6,8,10,12,14,17,20,24,30,40};\n    for(long long f : factors){\n        long long M = max(1LL, base * f / 10);\n        plans.push_back(make_shelf_rows_width_limit(w,h,M));\n    }\n\n    // Prefix-columns brute force for m<=12\n    int Mmax = min(N, 12);\n    for(int m=2;m<=Mmax;m++){\n        Plan pl = make_prefix_columns_bruteforce(w,h,m);\n        if(pl.predScore < (1LL<<61)) plans.push_back(std::move(pl));\n    }\n\n    // Online columns with several biases (wide/narrow)\n    long long scale = max(10000LL, sigma * 5);\n    vector<long long> biases = {-4*scale, -2*scale, -scale, 0, scale, 2*scale, 4*scale};\n    for(long long b : biases){\n        plans.push_back(make_online_columns(w,h,b,0,nullptr));\n        plans.push_back(make_online_columns(w,h,b,1,nullptr));\n    }\n\n    // Additional randomized online plans to increase diversity\n    for(int it=0; it<800; it++){\n        long long b = (long long)((int64_t)(rng()% (uint64_t)(8*scale+1)) - (int64_t)(4*scale));\n        int headerMode = (rng()&1ULL) ? 0 : 1;\n        plans.push_back(make_online_columns(w,h,b,headerMode,&rng));\n    }\n\n    // Sort by predicted score and drop duplicates\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b){\n        if(a.predScore != b.predScore) return a.predScore < b.predScore;\n        return a.tag < b.tag;\n    });\n\n    vector<Plan> uniq;\n    uniq.reserve(plans.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(plans.size()*2);\n\n    for(auto &pl : plans){\n        if((int)pl.ops.size() != N) continue;\n        uint64_t hv = hash_plan_ops(pl.ops);\n        if(seen.insert(hv).second){\n            uniq.push_back(std::move(pl));\n            if((int)uniq.size() >= 500) break; // enough diversity\n        }\n    }\n\n    // Interactive loop: output T plans (best first; then cycle through remaining/random-like ones)\n    for(int t=0;t<T;t++){\n        const Plan* pl;\n        if(t < (int)uniq.size()) pl = &uniq[t];\n        else pl = &uniq[t % (int)uniq.size()];\n\n        cout << pl->ops.size() << '\\n';\n        for(const auto& op : pl->ops){\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        long long Wp, Hp;\n        if(!(cin >> Wp >> Hp)) break; // safety for non-interactive runs\n        // We do not adapt online in this simple solver.\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 1000;\nstatic const uint8_t INF8 = 255;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    vector<bitset<MAXN>> adjbs(N);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        adjbs[u].set(v);\n        adjbs[v].set(u);\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // ------------------------------------------------------------\n    // Precompute distances up to H between all pairs (truncated BFS).\n    // dist[s][v] = hop distance if <=H else INF8.\n    // ------------------------------------------------------------\n    vector<vector<uint8_t>> dist(N, vector<uint8_t>(N, INF8));\n    {\n        deque<int> q;\n        vector<int> dd(N);\n        for (int s = 0; s < N; s++) {\n            fill(dd.begin(), dd.end(), -1);\n            dd[s] = 0;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                int dv = dd[v];\n                if (dv > H) continue;\n                dist[s][v] = (uint8_t)dv;\n                if (dv == H) continue;\n                for (int to : adj[v]) {\n                    if (dd[to] == -1) {\n                        dd[to] = dv + 1;\n                        q.push_back(to);\n                    }\n                }\n            }\n        }\n    }\n\n    auto covered_within_H = [&](const vector<int>& roots) -> bool {\n        for (int v = 0; v < N; v++) {\n            bool ok = false;\n            for (int r : roots) {\n                if (dist[r][v] != INF8) { ok = true; break; }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    };\n\n    // ------------------------------------------------------------\n    // Greedy radius-H dominating set (roots) + prune + local shift\n    // ------------------------------------------------------------\n    vector<int> roots;\n    {\n        vector<char> covered(N, 0);\n        int coveredCnt = 0;\n\n        while (coveredCnt < N) {\n            long long bestScore = -1;\n            int best = -1;\n\n            // recompute coverage gain for each candidate\n            for (int c = 0; c < N; c++) {\n                int gain = 0;\n                for (int v = 0; v < N; v++) {\n                    if (!covered[v] && dist[c][v] != INF8) gain++;\n                }\n                // prioritize coverage size, then prefer low beauty for root itself\n                long long score = 1000000LL * gain - 10LL * A[c];\n                if (score > bestScore) {\n                    bestScore = score;\n                    best = c;\n                }\n            }\n\n            roots.push_back(best);\n            for (int v = 0; v < N; v++) {\n                if (!covered[v] && dist[best][v] != INF8) {\n                    covered[v] = 1;\n                    coveredCnt++;\n                }\n            }\n        }\n\n        // prune redundant roots\n        shuffle(roots.begin(), roots.end(), rng);\n        for (int i = 0; i < (int)roots.size(); ) {\n            int old = roots[i];\n            vector<int> tmp;\n            tmp.reserve(roots.size() - 1);\n            for (int j = 0; j < (int)roots.size(); j++) if (j != i) tmp.push_back(roots[j]);\n            if (!tmp.empty() && covered_within_H(tmp)) {\n                roots.swap(tmp);\n                // do not increment i (new element at i)\n            } else {\n                i++;\n            }\n        }\n\n        // local root shifting: try to move each root to a nearby lower-A vertex (<=2 hops)\n        for (int idx = 0; idx < (int)roots.size(); idx++) {\n            int r = roots[idx];\n            vector<int> cand;\n            cand.reserve(N);\n            for (int v = 0; v < N; v++) {\n                if (dist[r][v] != INF8 && dist[r][v] <= 2) cand.push_back(v);\n            }\n            sort(cand.begin(), cand.end(), [&](int a, int b){\n                if (A[a] != A[b]) return A[a] < A[b];\n                return a < b;\n            });\n\n            int trials = min<int>(30, cand.size());\n            for (int t = 0; t < trials; t++) {\n                int c = cand[t];\n                if (c == r) break;\n                int backup = roots[idx];\n                roots[idx] = c;\n                if (covered_within_H(roots)) break;\n                roots[idx] = backup;\n            }\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Build initial forest with multi-source BFS (feasible depths)\n    // ------------------------------------------------------------\n    vector<int> parent(N, -2);\n    vector<int> depth(N, (int)1e9);\n    {\n        deque<int> q;\n        for (int r : roots) {\n            parent[r] = -1;\n            depth[r] = 0;\n            q.push_back(r);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (depth[v] == H) continue;\n            for (int to : adj[v]) {\n                if (depth[to] > depth[v] + 1) {\n                    depth[to] = depth[v] + 1;\n                    parent[to] = v;\n                    q.push_back(to);\n                }\n            }\n        }\n        // Safety: should not happen because roots dominate within H, but keep robust\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -2) {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Maintain children lists with O(1) erase by position\n    // ------------------------------------------------------------\n    vector<vector<int>> children(N);\n    vector<int> childPos(N, -1);\n\n    auto build_children = [&](){\n        for (int i = 0; i < N; i++) {\n            children[i].clear();\n            childPos[i] = -1;\n        }\n        for (int v = 0; v < N; v++) if (parent[v] != -1) {\n            int p = parent[v];\n            childPos[v] = (int)children[p].size();\n            children[p].push_back(v);\n        }\n    };\n\n    auto remove_child = [&](int p, int v){\n        int idx = childPos[v];\n        int last = children[p].back();\n        children[p][idx] = last;\n        childPos[last] = idx;\n        children[p].pop_back();\n        childPos[v] = -1;\n    };\n    auto add_child = [&](int p, int v){\n        childPos[v] = (int)children[p].size();\n        children[p].push_back(v);\n    };\n\n    build_children();\n\n    // leaves\n    vector<int> leaves;\n    vector<int> leafPos(N, -1);\n    vector<char> inLeaves(N, 0);\n\n    auto make_leaf = [&](int v){\n        if (inLeaves[v]) return;\n        inLeaves[v] = 1;\n        leafPos[v] = (int)leaves.size();\n        leaves.push_back(v);\n    };\n    auto unmake_leaf = [&](int v){\n        if (!inLeaves[v]) return;\n        int idx = leafPos[v];\n        int last = leaves.back();\n        leaves[idx] = last;\n        leafPos[last] = idx;\n        leaves.pop_back();\n        inLeaves[v] = 0;\n        leafPos[v] = -1;\n    };\n    auto refresh_leaf = [&](int v){\n        if (children[v].empty()) make_leaf(v);\n        else unmake_leaf(v);\n    };\n    for (int v = 0; v < N; v++) refresh_leaf(v);\n\n    // roots list maintenance (dynamic)\n    vector<int> rootsCur;\n    vector<int> rootPos(N, -1);\n    vector<char> inRoot(N, 0);\n    auto make_root = [&](int v){\n        if (inRoot[v]) return;\n        inRoot[v] = 1;\n        rootPos[v] = (int)rootsCur.size();\n        rootsCur.push_back(v);\n    };\n    auto unmake_root = [&](int v){\n        if (!inRoot[v]) return;\n        int idx = rootPos[v];\n        int last = rootsCur.back();\n        rootsCur[idx] = last;\n        rootPos[last] = idx;\n        rootsCur.pop_back();\n        inRoot[v] = 0;\n        rootPos[v] = -1;\n    };\n    for (int v = 0; v < N; v++) if (parent[v] == -1) make_root(v);\n\n    // Ancestor check (depth <= H, so O(H) is fine)\n    auto is_ancestor = [&](int anc, int node) -> bool {\n        int cur = node;\n        for (int step = 0; step <= H + 5 && cur != -1; step++) {\n            if (cur == anc) return true;\n            cur = parent[cur];\n        }\n        return false;\n    };\n\n    vector<int> sub;\n    auto collect_subtree = [&](int v, vector<int>& nodes) {\n        nodes.clear();\n        vector<int> st;\n        st.push_back(v);\n        while (!st.empty()) {\n            int x = st.back(); st.pop_back();\n            nodes.push_back(x);\n            for (int ch : children[x]) st.push_back(ch);\n        }\n    };\n\n    auto try_reattach = [&](int v, int u) -> bool {\n        if (u == v) return false;\n        if (!adjbs[v].test(u)) return false;\n        int ndv = depth[u] + 1;\n        if (ndv > H) return false;\n        int delta = ndv - depth[v];\n        if (delta <= 0) return false;\n        if (is_ancestor(v, u)) return false; // cycle\n\n        collect_subtree(v, sub);\n        int mx = 0;\n        for (int x : sub) mx = max(mx, depth[x]);\n        if (mx + delta > H) return false;\n\n        int oldp = parent[v];\n        if (oldp == -1) unmake_root(v);\n        if (oldp != -1) {\n            remove_child(oldp, v);\n            refresh_leaf(oldp);\n        }\n\n        parent[v] = u;\n        add_child(u, v);\n        refresh_leaf(u);\n\n        for (int x : sub) depth[x] += delta;\n\n        // v may still be leaf/non-leaf (children unchanged), no need to refresh v itself\n        return true;\n    };\n\n    // Rotation around p->c (c child of p), needs edge gp-c if gp exists.\n    vector<int> subC, subP;\n    vector<int> mark(N, 0);\n    int markToken = 1;\n\n    auto try_rotate = [&](int c) -> bool {\n        int p = parent[c];\n        if (p == -1) return false;\n        int gp = parent[p];\n        if (gp != -1 && !adjbs[gp].test(c)) return false;\n\n        collect_subtree(c, subC);\n        collect_subtree(p, subP);\n\n        markToken++;\n        for (int x : subC) mark[x] = markToken;\n\n        long long sumC = 0, sumOther = 0;\n        int mxOther = -1;\n        for (int x : subC) sumC += A[x];\n        for (int x : subP) {\n            if (mark[x] != markToken) {\n                sumOther += A[x];\n                mxOther = max(mxOther, depth[x]);\n            }\n        }\n        if (mxOther == -1) return false;\n        if (mxOther + 1 > H) return false;\n\n        long long deltaScore = sumOther - sumC; // score change in \u03a3 depth*A\n        if (deltaScore <= 0) return false;\n\n        // apply\n        remove_child(p, c);\n        refresh_leaf(p);\n\n        if (gp != -1) {\n            remove_child(gp, p);\n            refresh_leaf(gp);\n            parent[c] = gp;\n            add_child(gp, c);\n            refresh_leaf(gp);\n        } else {\n            // p was root, now c becomes root\n            parent[c] = -1;\n            make_root(c);\n            unmake_root(p);\n        }\n\n        parent[p] = c;\n        add_child(c, p);\n        refresh_leaf(c);\n\n        for (int x : subC) depth[x] -= 1;\n        for (int x : subP) if (mark[x] != markToken) depth[x] += 1;\n\n        return true;\n    };\n\n    auto best_deeper_neighbor = [&](int v) -> int {\n        int bestU = -1, bestD = -1;\n        for (int u : adj[v]) {\n            if (depth[u] >= H) continue;\n            int nd = depth[u] + 1;\n            if (nd <= depth[v]) continue;\n            if (is_ancestor(v, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    // ------------------------------------------------------------\n    // Deterministic \"push good vertices deeper\" warm-up\n    // ------------------------------------------------------------\n    {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int i, int j){\n            long long wi = 1LL * A[i] * (H - depth[i]);\n            long long wj = 1LL * A[j] * (H - depth[j]);\n            if (wi != wj) return wi > wj;\n            return A[i] > A[j];\n        });\n\n        int tries = min(N, 300);\n        for (int t = 0; t < tries; t++) {\n            int v = ord[t];\n            for (int rep = 0; rep < 2; rep++) {\n                int u = best_deeper_neighbor(v);\n                if (u == -1) break;\n                if (!try_reattach(v, u)) break;\n            }\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Local search\n    // ------------------------------------------------------------\n    Timer timer;\n    const double TL = 1.93;\n\n    auto pick_best_among = [&](const vector<int>& pool, int k) -> int {\n        if (pool.empty()) return -1;\n        int best = pool[rng() % pool.size()];\n        long long bestW = 1LL * A[best] * (H - depth[best]);\n        for (int i = 1; i < k; i++) {\n            int v = pool[rng() % pool.size()];\n            long long w = 1LL * A[v] * (H - depth[v]);\n            if (w > bestW) { bestW = w; best = v; }\n        }\n        return best;\n    };\n\n    vector<int> allNodes(N);\n    iota(allNodes.begin(), allNodes.end(), 0);\n\n    long long iters = 0;\n    while (timer.elapsed_sec() < TL) {\n        iters++;\n        uint64_t r = rng();\n        int mode = (int)(r % 100);\n\n        if (mode < 55) {\n            // leaf reattach, bias to high potential\n            int v = pick_best_among(leaves, 6);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) try_reattach(v, u);\n        } else if (mode < 80) {\n            // general reattach, bias to high potential\n            int v = pick_best_among(allNodes, 6);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) try_reattach(v, u);\n        } else if (mode < 90) {\n            // try to attach a root under another tree (reduce roots if feasible)\n            if (rootsCur.size() <= 1) continue;\n            int v = rootsCur[rng() % rootsCur.size()];\n            // try several neighbors and pick deepest feasible\n            int bestU = -1, bestD = -1;\n            for (int rep = 0; rep < 6; rep++) {\n                int u = adj[v][rng() % adj[v].size()];\n                if (u == v) continue;\n                if (depth[u] >= H) continue;\n                int ndv = depth[u] + 1;\n                if (ndv > H) continue;\n                if (is_ancestor(v, u)) continue; // u inside v component\n                if (depth[u] > bestD) {\n                    bestD = depth[u];\n                    bestU = u;\n                }\n            }\n            if (bestU != -1) try_reattach(v, bestU);\n        } else {\n            // rotation attempts (try a few random children edges)\n            int p = (int)(rng() % N);\n            if (children[p].empty()) continue;\n            int c = children[p][rng() % children[p].size()];\n            try_rotate(c);\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Final legality repair (cycle/height/edge)\n    // ------------------------------------------------------------\n    auto repair = [&](){\n        // Break cycles by coloring parent pointers.\n        vector<int> state(N, 0); // 0 unvisited, 1 visiting, 2 done\n        for (int v = 0; v < N; v++) {\n            if (state[v] != 0) continue;\n            int cur = v;\n            while (cur != -1 && state[cur] == 0) {\n                state[cur] = 1;\n                cur = parent[cur];\n            }\n            if (cur != -1 && state[cur] == 1) {\n                parent[v] = -1; // break\n            }\n            cur = v;\n            while (cur != -1 && state[cur] == 1) {\n                state[cur] = 2;\n                cur = parent[cur];\n            }\n        }\n\n        // Ensure parent edges exist.\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) continue;\n            if (!adjbs[v].test(parent[v])) parent[v] = -1;\n        }\n\n        // Rebuild children\n        build_children();\n\n        // Recompute depths from roots, cut if depth > H.\n        fill(depth.begin(), depth.end(), -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (parent[v] == -1) {\n            depth[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int ch : children[v]) {\n                depth[ch] = depth[v] + 1;\n                q.push_back(ch);\n            }\n        }\n        // unreachable -> root\n        for (int v = 0; v < N; v++) {\n            if (depth[v] == -1) {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n        }\n\n        // cut nodes deeper than H\n        bool changed = true;\n        int loop = 0;\n        while (changed && loop++ < 3) {\n            changed = false;\n            build_children();\n            fill(depth.begin(), depth.end(), -1);\n            q.clear();\n            for (int v = 0; v < N; v++) if (parent[v] == -1) {\n                depth[v] = 0;\n                q.push_back(v);\n            }\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                for (int ch : children[v]) {\n                    depth[ch] = depth[v] + 1;\n                    q.push_back(ch);\n                }\n            }\n            for (int v = 0; v < N; v++) {\n                if (depth[v] > H) {\n                    parent[v] = -1;\n                    changed = true;\n                }\n            }\n        }\n\n        // final parent-edge check again\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) continue;\n            if (!adjbs[v].test(parent[v])) parent[v] = -1;\n        }\n    };\n\n    repair();\n\n    for (int i = 0; i < N; i++) {\n        cout << parent[i] << (i + 1 == N ? '\\n' : ' ');\n    }\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\n\nstruct Option {\n    bool valid = false;\n    int type = -1; // 0:U col, 1:D col, 2:L row, 3:R row\n    int idx = -1;  // row or col index\n    int depth = 0; // required K\n};\n\nstruct Oni {\n    int r, c;\n    array<Option,4> opt; // 0:U 1:D 2:L 3:R\n    vector<int> feasibleDirs;\n    bool fixed = false;\n};\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto t = steady_clock::now() - st;\n    return duration<double>(t).count();\n}\n\nint computeCost(const vector<Oni>& onis, const vector<int>& dir,\n                array<int,N>& U, array<int,N>& D, array<int,N>& L, array<int,N>& R) {\n    U.fill(0); D.fill(0); L.fill(0); R.fill(0);\n    for (int k = 0; k < (int)onis.size(); k++) {\n        const auto &o = onis[k];\n        const Option &op = o.opt[dir[k]];\n        // assumed valid\n        if (op.type == 0) U[op.idx] = max(U[op.idx], op.depth);\n        else if (op.type == 1) D[op.idx] = max(D[op.idx], op.depth);\n        else if (op.type == 2) L[op.idx] = max(L[op.idx], op.depth);\n        else if (op.type == 3) R[op.idx] = max(R[op.idx], op.depth);\n    }\n    int sum = 0;\n    for (int i = 0; i < N; i++) sum += U[i] + D[i] + L[i] + R[i];\n    return sum;\n}\n\nint computeCostOnly(const vector<Oni>& onis, const vector<int>& dir) {\n    array<int,N> U,D,L,R;\n    return computeCost(onis, dir, U, D, L, R);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<string> C(n);\n    for (int i = 0; i < n; i++) cin >> C[i];\n\n    // Limits based on Fukunokami positions (fixed-safe depths)\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    left_limit.fill(N);\n    right_limit.fill(N);\n    up_limit.fill(N);\n    down_limit.fill(N);\n\n    // Row limits\n    for (int i = 0; i < N; i++) {\n        int first = N, last = -1;\n        for (int j = 0; j < N; j++) if (C[i][j] == 'o') {\n            first = min(first, j);\n            last = max(last, j);\n        }\n        left_limit[i] = first; // K <= first\n        if (last == -1) right_limit[i] = N;\n        else right_limit[i] = (N - 1 - last); // K <= dist from last o to right edge\n    }\n    // Col limits\n    for (int j = 0; j < N; j++) {\n        int first = N, last = -1;\n        for (int i = 0; i < N; i++) if (C[i][j] == 'o') {\n            first = min(first, i);\n            last = max(last, i);\n        }\n        up_limit[j] = first; // K <= first\n        if (last == -1) down_limit[j] = N;\n        else down_limit[j] = (N - 1 - last);\n    }\n\n    // Gather Oni\n    vector<Oni> onis;\n    onis.reserve(2*N);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (C[i][j] != 'x') continue;\n        Oni o;\n        o.r = i; o.c = j;\n\n        // U\n        {\n            int K = i + 1;\n            if (K <= up_limit[j]) {\n                o.opt[0] = Option{true, 0, j, K};\n                o.feasibleDirs.push_back(0);\n            }\n        }\n        // D\n        {\n            int K = N - i;\n            if (K <= down_limit[j]) {\n                o.opt[1] = Option{true, 1, j, K};\n                o.feasibleDirs.push_back(1);\n            }\n        }\n        // L\n        {\n            int K = j + 1;\n            if (K <= left_limit[i]) {\n                o.opt[2] = Option{true, 2, i, K};\n                o.feasibleDirs.push_back(2);\n            }\n        }\n        // R\n        {\n            int K = N - j;\n            if (K <= right_limit[i]) {\n                o.opt[3] = Option{true, 3, i, K};\n                o.feasibleDirs.push_back(3);\n            }\n        }\n\n        // Guaranteed at least one feasible direction by problem statement\n        if (o.feasibleDirs.empty()) {\n            // Fallback (should not happen)\n            // But to avoid crashing: assign Up with K=1 (unsafe), still.\n            o.feasibleDirs.push_back(0);\n            o.opt[0] = Option{true,0,j,1};\n        }\n        if (o.feasibleDirs.size() == 1) o.fixed = true;\n\n        onis.push_back(o);\n    }\n\n    int M = (int)onis.size();\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937_64 rng(seed);\n\n    auto randInt = [&](int lo, int hi)->int{ // inclusive\n        std::uniform_int_distribution<int> dist(lo, hi);\n        return dist(rng);\n    };\n    auto randDouble = [&]()->double{\n        std::uniform_real_distribution<double> dist(0.0, 1.0);\n        return dist(rng);\n    };\n\n    // Initial assignment: minimal required depth (greedy)\n    vector<int> curDir(M, 0);\n    for (int k = 0; k < M; k++) {\n        int bestd = -1;\n        int bestK = INT_MAX;\n        // slight randomness among ties\n        vector<int> ties;\n        for (int d : onis[k].feasibleDirs) {\n            int dep = onis[k].opt[d].depth;\n            if (dep < bestK) {\n                bestK = dep;\n                ties.clear();\n                ties.push_back(d);\n            } else if (dep == bestK) {\n                ties.push_back(d);\n            }\n        }\n        bestd = ties[randInt(0, (int)ties.size()-1)];\n        curDir[k] = bestd;\n    }\n\n    int curCost = computeCostOnly(onis, curDir);\n    vector<int> bestDir = curDir;\n    int bestCost = curCost;\n\n    // Simulated annealing\n    double start = now_sec();\n    double TL = 1.90; // aim under 2s\n    const double T0 = 30.0;\n    const double T1 = 0.5;\n\n    while (true) {\n        double t = now_sec() - start;\n        if (t >= TL) break;\n        double p = t / TL;\n        double temp = T0 * (1.0 - p) + T1 * p;\n\n        int k = randInt(0, M-1);\n        if (onis[k].fixed) continue;\n\n        const auto &fds = onis[k].feasibleDirs;\n        if ((int)fds.size() <= 1) continue;\n\n        int old = curDir[k];\n        int nd = old;\n        // pick different feasible direction\n        for (int tries = 0; tries < 10; tries++) {\n            nd = fds[randInt(0, (int)fds.size()-1)];\n            if (nd != old) break;\n        }\n        if (nd == old) continue;\n\n        curDir[k] = nd;\n        int newCost = computeCostOnly(onis, curDir);\n        int delta = newCost - curCost;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(- (double)delta / temp);\n            if (randDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curCost = newCost;\n            if (curCost < bestCost) {\n                bestCost = curCost;\n                bestDir = curDir;\n            }\n        } else {\n            curDir[k] = old;\n        }\n    }\n\n    // Final coordinate descent (greedy local improvement)\n    curDir = bestDir;\n    curCost = bestCost;\n    bool improved = true;\n    for (int it = 0; it < 30 && improved; it++) {\n        improved = false;\n        for (int k = 0; k < M; k++) {\n            if (onis[k].fixed) continue;\n            int old = curDir[k];\n            int bestd = old;\n            int bestLocalCost = curCost;\n            for (int nd : onis[k].feasibleDirs) {\n                if (nd == old) continue;\n                curDir[k] = nd;\n                int cst = computeCostOnly(onis, curDir);\n                if (cst < bestLocalCost) {\n                    bestLocalCost = cst;\n                    bestd = nd;\n                }\n            }\n            curDir[k] = old;\n            if (bestd != old) {\n                curDir[k] = bestd;\n                curCost = bestLocalCost;\n                improved = true;\n            }\n        }\n    }\n    bestDir = curDir;\n    bestCost = curCost;\n\n    // Build depths from best assignment\n    array<int,N> U,D,L,R;\n    computeCost(onis, bestDir, U, D, L, R);\n\n    // Output operations\n    vector<pair<char,int>> ans;\n    ans.reserve(2 * bestCost);\n\n    auto addRepeat = [&](char ch, int idx, int k) {\n        for (int t = 0; t < k; t++) ans.push_back({ch, idx});\n    };\n\n    // Columns: top deletions then bottom deletions\n    for (int j = 0; j < N; j++) {\n        int k = U[j];\n        if (k > 0) {\n            addRepeat('U', j, k);\n            addRepeat('D', j, k);\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int k = D[j];\n        if (k > 0) {\n            addRepeat('D', j, k);\n            addRepeat('U', j, k);\n        }\n    }\n\n    // Rows: left deletions then right deletions\n    for (int i = 0; i < N; i++) {\n        int k = L[i];\n        if (k > 0) {\n            addRepeat('L', i, k);\n            addRepeat('R', i, k);\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        int k = R[i];\n        if (k > 0) {\n            addRepeat('R', i, k);\n            addRepeat('L', i, k);\n        }\n    }\n\n    // Safety: must be <= 4N^2\n    // (Should always hold because each Oni contributes depth<=20 and there are 40 Oni.)\n    if ((int)ans.size() > 4 * N * N) {\n        // Fallback: output nothing (would score poorly but avoid WA by too many ops).\n        // However, this should not happen.\n        ans.clear();\n    }\n\n    for (auto [ch, idx] : ans) {\n        cout << ch << \" \" << idx << \"\\n\";\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 100;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int mod) { return (int)(nextU64() % (uint64_t)mod); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline int iabs_int(int x) { return x < 0 ? -x : x; }\nstatic inline long long iabs_ll(long long x) { return x < 0 ? -x : x; }\n\nstruct Plan {\n    array<int, N> a;\n    array<int, N> b;\n};\n\nint simulate_plan(const Plan& p, int L, const array<int, N>& T, array<int, N>& cnt) {\n    cnt.fill(0);\n    int cur = 0;\n    cnt[0] = 1;\n    for (int step = 1; step < L; ++step) {\n        int x = cur;\n        cur = (cnt[x] & 1) ? p.a[x] : p.b[x];\n        ++cnt[cur];\n    }\n    int E = 0;\n    for (int i = 0; i < N; ++i) E += iabs_int(cnt[i] - T[i]);\n    return E;\n}\n\n// Kosaraju SCC on \"core nodes\", edges are a[v], b[v] (assumed to be within core for v in core)\nint scc_core(const Plan& p, const vector<int>& core, const array<char, N>& inCore,\n             array<int, N>& compOut) {\n    vector<int> nodes = core;\n    int K = (int)nodes.size();\n    if (K == 0) return 0;\n    // map node -> idx not needed; use inCore check\n    vector<vector<int>> rg(N); rg.assign(N, {});\n    vector<vector<int>> g(N);  g.assign(N, {});\n    for (int v : nodes) {\n        int to1 = p.a[v], to2 = p.b[v];\n        g[v].push_back(to1);\n        g[v].push_back(to2);\n        rg[to1].push_back(v);\n        rg[to2].push_back(v);\n    }\n    vector<char> vis(N, 0);\n    vector<int> order; order.reserve(K);\n\n    auto dfs1 = [&](auto&& self, int v) -> void {\n        vis[v] = 1;\n        for (int to : g[v]) if (inCore[to] && !vis[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int v : nodes) if (!vis[v]) dfs1(dfs1, v);\n\n    compOut.fill(-1);\n    int compCnt = 0;\n    auto dfs2 = [&](auto&& self, int v) -> void {\n        compOut[v] = compCnt;\n        for (int to : rg[v]) if (inCore[to] && compOut[to] == -1) self(self, to);\n    };\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (compOut[v] == -1) {\n            dfs2(dfs2, v);\n            ++compCnt;\n        }\n    }\n    return compCnt;\n}\n\n// Static balance objective on core:\n// incomingW[j] = sum_{i in core} T[i] * [a_i==j] + T[i] * [b_i==j]\n// want incomingW[j] ~= 2*T[j]\nstruct StaticBalance {\n    array<long long, N> D; // D[j] = incomingW[j] - 2*T[j], only meaningful on core\n    long long F = 0;       // sum |D[j]| over core\n};\n\nStaticBalance compute_static_balance(const Plan& p, const array<int, N>& T,\n                                     const vector<int>& core, const array<char, N>& inCore) {\n    array<long long, N> incoming{};\n    incoming.fill(0);\n    for (int i : core) {\n        incoming[p.a[i]] += T[i];\n        incoming[p.b[i]] += T[i];\n    }\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = incoming[j] - 2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n    return sb;\n}\n\ninline long long delta_move_edge(long long Dold, long long Dnew, int w) {\n    // Move one edge of weight w: D_old -= w, D_new += w\n    long long before = iabs_ll(Dold) + iabs_ll(Dnew);\n    long long after  = iabs_ll(Dold - w) + iabs_ll(Dnew + w);\n    return after - before;\n}\n\ninline void apply_move_edge(StaticBalance& sb, int oldDest, int newDest, int w) {\n    // assumes oldDest,newDest are in core and w>=0\n    sb.F -= iabs_ll(sb.D[oldDest]);\n    sb.D[oldDest] -= w;\n    sb.F += iabs_ll(sb.D[oldDest]);\n\n    sb.F -= iabs_ll(sb.D[newDest]);\n    sb.D[newDest] += w;\n    sb.F += iabs_ll(sb.D[newDest]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, L;\n    cin >> Nin >> L;\n    array<int, N> T{};\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    uint64_t seed = 123456789ULL;\n    for (int i = 0; i < N; ++i) seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    RNG rng(seed);\n\n    auto time_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    // Core: nodes with positive target\n    array<char, N> inCore{};\n    inCore.fill(0);\n    vector<int> core;\n    core.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        if (T[i] > 0) { inCore[i] = 1; core.push_back(i); }\n    }\n\n    // Edge case: if somehow core is empty (shouldn't happen since sum T = L), make core {0}\n    if (core.empty()) { inCore[0] = 1; core.push_back(0); }\n\n    int hub = core[0];\n    for (int v : core) if (T[v] > T[hub]) hub = v;\n\n    Plan p;\n    p.a.fill(hub);\n    p.b.fill(hub);\n\n    // ----- Initial construction: greedy best-improvement per edge on static objective -----\n    // Initialize D = -2*T on core\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = -2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n\n    // Assign edges for core nodes to reduce F\n    for (int i : core) {\n        int w = T[i];\n        for (int e = 0; e < 2; ++e) {\n            int bestJ = core[rng.nextInt((int)core.size())];\n            long long bestDelta = (1LL<<62);\n\n            // If weight is 0 (shouldn't inside core), just random to help connectivity later\n            if (w == 0) {\n                bestJ = core[rng.nextInt((int)core.size())];\n                bestDelta = 0;\n            } else {\n                for (int j : core) {\n                    // currently edge points to hub, but we are building from scratch: treat as adding w to j\n                    long long before = iabs_ll(sb.D[j]);\n                    long long after  = iabs_ll(sb.D[j] + w);\n                    long long delta = after - before;\n                    if (delta < bestDelta || (delta == bestDelta && rng.nextInt(8) == 0)) {\n                        bestDelta = delta;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            // Apply: oldDest was \"none\" (incoming 0), but our sb.D already includes only demand.\n            // So just D[bestJ] += w, update F accordingly.\n            sb.F -= iabs_ll(sb.D[bestJ]);\n            sb.D[bestJ] += w;\n            sb.F += iabs_ll(sb.D[bestJ]);\n\n            if (e == 0) p.a[i] = bestJ;\n            else p.b[i] = bestJ;\n        }\n    }\n\n    // Non-core nodes: point to hub (won't be visited if core is closed and 0 in core; if 0 not in core, it is transient)\n    for (int i = 0; i < N; ++i) if (!inCore[i]) {\n        p.a[i] = hub;\n        p.b[i] = hub;\n    }\n\n    // If 0 is not in core, ensure it enters core immediately and never referenced by core (we keep core closed)\n    if (!inCore[0]) {\n        p.a[0] = hub;\n        p.b[0] = hub;\n    }\n\n    // Recompute sb properly from plan (for correctness after our incremental build)\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Fast SA on static balance objective -----\n    // Periodically keep sorted lists of deficits\n    vector<int> core_sorted = core;\n\n    auto resort_core = [&]() {\n        core_sorted = core;\n        sort(core_sorted.begin(), core_sorted.end(), [&](int x, int y) {\n            return sb.D[x] < sb.D[y]; // more negative first (needs incoming)\n        });\n    };\n    resort_core();\n\n    // Weighted source selection among core based on T[i]\n    vector<long long> pref;\n    pref.reserve(core.size()+1);\n    auto build_pref = [&]() {\n        pref.assign(core.size()+1, 0);\n        for (int k = 0; k < (int)core.size(); ++k) {\n            pref[k+1] = pref[k] + max(1, T[core[k]]); // avoid all-zero\n        }\n    };\n    build_pref();\n\n    auto pick_core_weighted = [&]() -> int {\n        long long sum = pref.back();\n        long long r = (long long)(rng.nextU64() % (uint64_t)sum);\n        int k = (int)(upper_bound(pref.begin(), pref.end(), r) - pref.begin()) - 1;\n        if (k < 0) k = 0;\n        if (k >= (int)core.size()) k = (int)core.size()-1;\n        return core[k];\n    };\n\n    const double STATIC_END = 0.65; // seconds budget for static stage\n    long long bestF = sb.F;\n    Plan bestStatic = p;\n\n    int iter = 0;\n    while (elapsedSec() < STATIC_END && !core.empty()) {\n        ++iter;\n        if ((iter & 1023) == 0) resort_core();\n\n        int i = (rng.nextInt(100) < 75) ? pick_core_weighted() : core[rng.nextInt((int)core.size())];\n        int w = T[i];\n        int e = rng.nextInt(2);\n        int& edge = (e == 0 ? p.a[i] : p.b[i]);\n        int oldDest = edge;\n\n        // choose new destination among a small candidate set\n        int candCount = 10;\n        long long bestDelta = (1LL<<62);\n        int bestDest = oldDest;\n\n        for (int t = 0; t < candCount; ++t) {\n            int newDest;\n            if (rng.nextInt(100) < 75) {\n                // pick from most-negative (needs incoming)\n                int idx = rng.nextInt(min(20, (int)core_sorted.size()));\n                newDest = core_sorted[idx];\n            } else {\n                newDest = core[rng.nextInt((int)core.size())];\n            }\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d < bestDelta) { bestDelta = d; bestDest = newDest; }\n        }\n        if (bestDest == oldDest) continue;\n\n        // SA acceptance on static objective\n        double tcur = min(1.0, elapsedSec() / STATIC_END);\n        double temp = 2000.0 * pow(1.0 / 2000.0, tcur); // 2000 -> 1\n        bool accept = false;\n        if (bestDelta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)bestDelta / temp)) accept = true;\n\n        if (!accept) continue;\n\n        // apply\n        apply_move_edge(sb, oldDest, bestDest, w);\n        edge = bestDest;\n\n        if (sb.F < bestF) {\n            bestF = sb.F;\n            bestStatic = p;\n        }\n    }\n    p = bestStatic;\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Repair: make core strongly connected (to avoid falling into a sink SCC subset) -----\n    array<int, N> comp{};\n    int compCnt = scc_core(p, core, inCore, comp);\n    int repairRounds = 0;\n    while (compCnt > 1 && elapsedSec() < 0.90 && repairRounds < 50) {\n        ++repairRounds;\n\n        vector<int> rep(compCnt, -1);\n        for (int v : core) {\n            int c = comp[v];\n            if (rep[c] == -1 || T[v] < T[rep[c]]) rep[c] = v;\n        }\n        // connect components in a cycle using minimal-static-delta edge rewires\n        for (int c = 0; c < compCnt; ++c) {\n            int from = rep[c];\n            int to = rep[(c+1) % compCnt];\n            if (from == -1 || to == -1) continue;\n            if (p.a[from] == to || p.b[from] == to) continue;\n\n            int w = T[from];\n\n            // choose whether to replace a or b to minimize static damage\n            long long da = delta_move_edge(sb.D[p.a[from]], sb.D[to], w);\n            long long db = delta_move_edge(sb.D[p.b[from]], sb.D[to], w);\n\n            if (da <= db) {\n                int old = p.a[from];\n                apply_move_edge(sb, old, to, w);\n                p.a[from] = to;\n            } else {\n                int old = p.b[from];\n                apply_move_edge(sb, old, to, w);\n                p.b[from] = to;\n            }\n        }\n\n        // small local clean-up on static objective after rewiring\n        for (int k = 0; k < 2000; ++k) {\n            int i = pick_core_weighted();\n            int w = T[i];\n            int e = rng.nextInt(2);\n            int& edge = (e == 0 ? p.a[i] : p.b[i]);\n            int oldDest = edge;\n\n            int newDest = core[rng.nextInt((int)core.size())];\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d <= 0) {\n                apply_move_edge(sb, oldDest, newDest, w);\n                edge = newDest;\n            }\n        }\n\n        compCnt = scc_core(p, core, inCore, comp);\n    }\n\n    // ----- Exact simulation SA on real objective -----\n    array<int, N> curCnt{}, bestCnt{}, tmpCnt{};\n    Plan curP = p, bestP = p;\n    int curE = simulate_plan(curP, L, T, curCnt);\n    int bestE = curE;\n    bestCnt = curCnt;\n\n    auto pick_x = [&]() -> int {\n        // choose among core (if 0 not in core, it is only visited once; no need to optimize edges by counts)\n        if (core.size() == 1) return core[0];\n        // rejection sampling biased by visit counts\n        int maxC = 1;\n        for (int v : core) maxC = max(maxC, curCnt[v]);\n        while (true) {\n            int v = core[rng.nextInt((int)core.size())];\n            if (rng.nextInt(maxC) < curCnt[v]) return v;\n        }\n    };\n\n    auto pick_dest_deficit = [&]() -> int {\n        // pick a destination in core biased to under-visited nodes\n        int maxD = 1;\n        for (int v : core) maxD = max(maxD, max(0, T[v] - curCnt[v]));\n        for (int tries = 0; tries < 50; ++tries) {\n            int v = core[rng.nextInt((int)core.size())];\n            int d = max(0, T[v] - curCnt[v]);\n            if (rng.nextInt(maxD) < d + 1) return v;\n        }\n        return core[rng.nextInt((int)core.size())];\n    };\n\n    auto core_strong_connected = [&](const Plan& pp) -> bool {\n        if (core.size() <= 1) return true;\n        // BFS from some start in core\n        int s = core[0];\n        vector<char> vis(N, 0);\n        deque<int> dq;\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            int to1 = pp.a[v], to2 = pp.b[v];\n            if (inCore[to1] && !vis[to1]) { vis[to1] = 1; dq.push_back(to1); }\n            if (inCore[to2] && !vis[to2]) { vis[to2] = 1; dq.push_back(to2); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n\n        // reverse BFS\n        vector<vector<int>> rg(N);\n        for (int v : core) {\n            rg[pp.a[v]].push_back(v);\n            rg[pp.b[v]].push_back(v);\n        }\n        fill(vis.begin(), vis.end(), 0);\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (int u : rg[v]) if (inCore[u] && !vis[u]) { vis[u] = 1; dq.push_back(u); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n        return true;\n    };\n\n    const double DYN_START = elapsedSec();\n    while (elapsedSec() < TIME_LIMIT) {\n        double t = (elapsedSec() - DYN_START) / max(1e-9, (TIME_LIMIT - DYN_START));\n        t = min(1.0, max(0.0, t));\n        double temp = 6000.0 * pow(30.0 / 6000.0, t);\n\n        int type = rng.nextInt(100);\n        int x1=-1, e1=0, old1=-1;\n        int x2=-1, e2=0, old2=-1;\n        int olda=-1, oldb=-1;\n\n        if (type < 72) {\n            // change one edge\n            x1 = pick_x();\n            e1 = rng.nextInt(2);\n            int& edge = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            old1 = edge;\n            int y = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y == old1) continue;\n            edge = y;\n        } else if (type < 92) {\n            // swap two edges\n            x1 = pick_x(); e1 = rng.nextInt(2);\n            x2 = pick_x(); e2 = rng.nextInt(2);\n            int& ed1 = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            int& ed2 = (e2==0 ? curP.a[x2] : curP.b[x2]);\n            old1 = ed1; old2 = ed2;\n            if (old1 == old2) continue;\n            ed1 = old2; ed2 = old1;\n        } else {\n            // reset both edges of one node\n            x1 = pick_x();\n            olda = curP.a[x1];\n            oldb = curP.b[x1];\n            int y1 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            int y2 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y1 == olda && y2 == oldb) continue;\n            curP.a[x1] = y1;\n            curP.b[x1] = y2;\n        }\n\n        // Keep core closed (should already hold by how we pick destinations), and keep core strongly connected\n        if (!core_strong_connected(curP)) {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n            continue;\n        }\n\n        int newE = simulate_plan(curP, L, T, tmpCnt);\n        int delta = newE - curE;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)delta / temp)) accept = true;\n\n        if (accept) {\n            curE = newE;\n            curCnt = tmpCnt;\n            if (curE < bestE) {\n                bestE = curE;\n                bestP = curP;\n                bestCnt = curCnt;\n            }\n        } else {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n        }\n    }\n\n    // Output best plan found\n    for (int i = 0; i < N; ++i) {\n        cout << bestP.a[i] << ' ' << bestP.b[i] << \"\\n\";\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\n\nusing namespace std;\n\nstruct City {\n    int lx, rx, ly, ry;\n    int cx, cy;          // estimated center\n    uint32_t morton;     // Z-order key on center\n};\n\nstatic inline uint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nstatic inline uint32_t morton2D(uint32_t x, uint32_t y) {\n    return part1by1(x) | (part1by1(y) << 1);\n}\n\nstruct EdgeW {\n    int a, b;\n    uint16_t w;\n};\n\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<City> cities;\n\n    vector<uint16_t> distMat; // center-based floor euclidean; N*N\n    int q_used = 0;\n\n    vector<vector<int>> groups;\n    vector<vector<pair<int,int>>> queryEdges;\n    vector<char> fullQueried;\n\n    // per-group fallback (estimated MST) edges\n    vector<vector<pair<int,int>>> fallbackEdges;\n    vector<vector<EdgeW>> fallbackEdgesW; // also keep weights for query planning\n\n    uint16_t dist_est(int a, int b) const {\n        return distMat[a * N + b];\n    }\n\n    uint16_t rect_mindist(int a, int b) const {\n        // lower bound on Euclidean distance between two rectangles\n        const auto &A = cities[a];\n        const auto &B = cities[b];\n        long long dx = 0, dy = 0;\n        if (A.rx < B.lx) dx = (long long)B.lx - A.rx;\n        else if (B.rx < A.lx) dx = (long long)A.lx - B.rx;\n        if (A.ry < B.ly) dy = (long long)B.ly - A.ry;\n        else if (B.ry < A.ly) dy = (long long)A.ly - B.ry;\n        long long sq = dx*dx + dy*dy;\n        int d = (int)floor(sqrt((double)sq));\n        if (d < 0) d = 0;\n        if (d > 65535) d = 65535;\n        return (uint16_t)d;\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int v : subset) cout << \" \" << v;\n        cout << \"\\n\" << flush;\n\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, l - 1));\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            cin >> a >> b;\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        q_used++;\n        return edges;\n    }\n\n    // Prim on complete graph with center distances: return total weight, and optionally edges\n    long long prim_build(const vector<int>& nodes, vector<pair<int,int>>* outEdges, vector<EdgeW>* outEdgesW) {\n        int s = (int)nodes.size();\n        if (outEdges) outEdges->clear();\n        if (outEdgesW) outEdgesW->clear();\n        if (s <= 1) return 0;\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        vector<uint16_t> minc(s, INF);\n        vector<int> parent(s, -1);\n        vector<char> used(s, false);\n\n        minc[0] = 0;\n        long long sum = 0;\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) if (!used[i]) {\n                if (v == -1 || minc[i] < minc[v]) v = i;\n            }\n            used[v] = true;\n            if (parent[v] != -1) {\n                int a = nodes[v], b = nodes[parent[v]];\n                uint16_t w = dist_est(a, b);\n                sum += (int)w;\n                if (a > b) swap(a, b);\n                if (outEdges) outEdges->push_back({a, b});\n                if (outEdgesW) outEdgesW->push_back({a, b, w});\n            }\n            for (int u = 0; u < s; u++) if (!used[u]) {\n                uint16_t d = dist_est(nodes[v], nodes[u]);\n                if (d < minc[u]) {\n                    minc[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n        return sum;\n    }\n\n    long long eval_groups(const vector<vector<int>>& gr) {\n        long long total = 0;\n        for (int k = 0; k < M; k++) {\n            total += prim_build(gr[k], nullptr, nullptr);\n        }\n        return total;\n    }\n\n    vector<vector<int>> build_groups_sweep(const vector<int>& order) {\n        vector<vector<int>> gr(M);\n        int idx = 0;\n        for (int k = 0; k < M; k++) {\n            gr[k].reserve(G[k]);\n            for (int t = 0; t < G[k]; t++) {\n                gr[k].push_back(order[idx++]);\n            }\n        }\n        return gr;\n    }\n\n    vector<vector<int>> build_groups_grow(const vector<int>& seedOrder, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        vector<char> used(N, false);\n        vector<uint16_t> best(N);\n\n        int ptr = 0;\n        auto next_seed = [&]() -> int {\n            while (ptr < N && used[seedOrder[ptr]]) ptr++;\n            if (ptr >= N) {\n                for (int i = 0; i < N; i++) if (!used[i]) return i;\n                return -1;\n            }\n            return seedOrder[ptr];\n        };\n\n        for (int gid : groupOrder) {\n            int need = G[gid];\n            gr[gid].clear();\n            gr[gid].reserve(need);\n\n            int seed = next_seed();\n            if (seed < 0) break;\n            used[seed] = true;\n            gr[gid].push_back(seed);\n\n            const uint16_t INF = numeric_limits<uint16_t>::max();\n            for (int v = 0; v < N; v++) best[v] = used[v] ? INF : dist_est(seed, v);\n\n            for (int t = 1; t < need; t++) {\n                int pick = -1;\n                uint16_t bd = INF;\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = best[v];\n                    if (pick == -1 || d < bd) { bd = d; pick = v; }\n                }\n                if (pick < 0) break;\n                used[pick] = true;\n                gr[gid].push_back(pick);\n\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = dist_est(pick, v);\n                    if (d < best[v]) best[v] = d;\n                }\n            }\n        }\n        return gr;\n    }\n\n    // build a query subset = anchor + nearest (L-1) nodes in the group (by center dist)\n    vector<int> make_local_subset(int k, int anchor) {\n        const auto &nodes = groups[k];\n        int s = (int)nodes.size();\n        int want = min(L, s);\n        vector<pair<uint16_t,int>> cand;\n        cand.reserve(s-1);\n        for (int v : nodes) if (v != anchor) {\n            cand.emplace_back(dist_est(anchor, v), v);\n        }\n        int take = want - 1;\n        if (take <= 0) return {anchor};\n        if ((int)cand.size() > take) {\n            nth_element(cand.begin(), cand.begin() + take, cand.end());\n            cand.resize(take);\n        }\n        sort(cand.begin(), cand.end()); // stable-ish\n        vector<int> subset;\n        subset.reserve(1 + (int)cand.size());\n        subset.push_back(anchor);\n        for (auto &p : cand) subset.push_back(p.second);\n        return subset;\n    }\n\n    vector<pair<int,int>> build_final_tree(int k) {\n        const vector<int>& nodes = groups[k];\n        int s = (int)nodes.size();\n        vector<pair<int,int>> result;\n        if (s <= 1) return result;\n        if (s == 2) {\n            int a = nodes[0], b = nodes[1];\n            if (a > b) swap(a,b);\n            result.push_back({a,b});\n            return result;\n        }\n\n        if (fullQueried[k]) {\n            // exact MST of the group\n            result = queryEdges[k];\n            if ((int)result.size() == s - 1) return result;\n        }\n\n        // Map global city id -> local index 0..s-1\n        vector<int> pos(N, -1);\n        for (int i = 0; i < s; i++) pos[nodes[i]] = i;\n\n        auto normalize_dedup = [&](vector<pair<int,int>>& es) {\n            for (auto &e : es) if (e.first > e.second) swap(e.first, e.second);\n            sort(es.begin(), es.end());\n            es.erase(unique(es.begin(), es.end()), es.end());\n        };\n\n        vector<pair<int,int>> qE = queryEdges[k];\n        vector<pair<int,int>> fb = fallbackEdges[k];\n        normalize_dedup(qE);\n        normalize_dedup(fb);\n\n        // Sort query edges by a more robust key: rect lower bound first, then center dist.\n        sort(qE.begin(), qE.end(), [&](const auto& A, const auto& B){\n            uint16_t a1 = rect_mindist(A.first, A.second);\n            uint16_t b1 = rect_mindist(B.first, B.second);\n            if (a1 != b1) return a1 < b1;\n            uint16_t a2 = dist_est(A.first, A.second);\n            uint16_t b2 = dist_est(B.first, B.second);\n            if (a2 != b2) return a2 < b2;\n            return A < B;\n        });\n        // fallback already an MST under center distances; add lighter first for nicer DSU behavior\n        sort(fb.begin(), fb.end(), [&](const auto& A, const auto& B){\n            uint16_t a2 = dist_est(A.first, A.second);\n            uint16_t b2 = dist_est(B.first, B.second);\n            if (a2 != b2) return a2 < b2;\n            return A < B;\n        });\n\n        atcoder::dsu dsu(s);\n        auto try_add = [&](int a, int b) {\n            int pa = pos[a], pb = pos[b];\n            if (pa < 0 || pb < 0) return false;\n            if (dsu.same(pa, pb)) return false;\n            dsu.merge(pa, pb);\n            if (a > b) swap(a, b);\n            result.emplace_back(a, b);\n            return true;\n        };\n\n        for (auto &e : qE) try_add(e.first, e.second);\n        for (auto &e : fb) try_add(e.first, e.second);\n\n        // Safety: if still not connected, connect components greedily (should be very rare)\n        if ((int)result.size() != s - 1) {\n            vector<int> leaders;\n            leaders.reserve(s);\n            for (int i = 0; i < s; i++) leaders.push_back(dsu.leader(i));\n            sort(leaders.begin(), leaders.end());\n            leaders.erase(unique(leaders.begin(), leaders.end()), leaders.end());\n\n            while ((int)leaders.size() > 1 && (int)result.size() < s - 1) {\n                int la = leaders.back(); leaders.pop_back();\n                int besta = -1, bestb = -1;\n                uint16_t bestd = numeric_limits<uint16_t>::max();\n                int aNode = nodes[la];\n                for (int lb : leaders) {\n                    int bNode = nodes[lb];\n                    uint16_t d = dist_est(aNode, bNode);\n                    if (d < bestd) { bestd = d; besta = la; bestb = lb; }\n                }\n                if (besta == -1) break;\n                try_add(nodes[besta], nodes[bestb]);\n\n                // rebuild leaders\n                leaders.clear();\n                vector<char> seen(s, false);\n                for (int i = 0; i < s; i++) {\n                    int r = dsu.leader(i);\n                    if (!seen[r]) { seen[r] = true; leaders.push_back(r); }\n                }\n            }\n        }\n\n        if ((int)result.size() > s - 1) result.resize(s - 1);\n        return result;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        cities.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto &c = cities[i];\n            cin >> c.lx >> c.rx >> c.ly >> c.ry;\n            c.cx = (c.lx + c.rx) / 2;\n            c.cy = (c.ly + c.ry) / 2;\n            uint32_t x = (uint32_t)min(16383, max(0, c.cx));\n            uint32_t y = (uint32_t)min(16383, max(0, c.cy));\n            c.morton = morton2D(x, y);\n        }\n\n        // Precompute center distance matrix\n        distMat.assign((size_t)N * N, 0);\n        for (int i = 0; i < N; i++) {\n            distMat[i * N + i] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = cities[i].cx - cities[j].cx;\n                long long dy = cities[i].cy - cities[j].cy;\n                long long sq = dx * dx + dy * dy;\n                int d = (int)floor(sqrt((double)sq));\n                if (d < 0) d = 0;\n                if (d > 65535) d = 65535;\n                distMat[i * N + j] = (uint16_t)d;\n                distMat[j * N + i] = (uint16_t)d;\n            }\n        }\n\n        // Precompute a few global orderings for candidates\n        vector<int> ord_morton(N), ord_x(N), ord_y(N), ord_xy1(N), ord_xy2(N);\n        iota(ord_morton.begin(), ord_morton.end(), 0);\n        iota(ord_x.begin(), ord_x.end(), 0);\n        iota(ord_y.begin(), ord_y.end(), 0);\n        iota(ord_xy1.begin(), ord_xy1.end(), 0);\n        iota(ord_xy2.begin(), ord_xy2.end(), 0);\n\n        sort(ord_morton.begin(), ord_morton.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_x.begin(), ord_x.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_y.begin(), ord_y.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ord_xy1.begin(), ord_xy1.end(), [&](int a, int b){\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            return a < b;\n        });\n        sort(ord_xy2.begin(), ord_xy2.end(), [&](int a, int b){\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n\n        // Group order variants for \"grow\" method\n        vector<int> go_given(M), go_desc(M);\n        iota(go_given.begin(), go_given.end(), 0);\n        iota(go_desc.begin(), go_desc.end(), 0);\n        sort(go_desc.begin(), go_desc.end(), [&](int a, int b){\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        // deterministic RNG based on input\n        uint64_t h = 1469598103934665603ULL;\n        for (int i = 0; i < N; i++) {\n            h ^= (uint64_t)cities[i].cx + 10007ULL * (uint64_t)cities[i].cy;\n            h *= 1099511628211ULL;\n        }\n        std::mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n        // Generate candidate partitions\n        vector<vector<vector<int>>> candidates;\n        candidates.reserve(20);\n\n        // sweeps\n        candidates.push_back(build_groups_sweep(ord_morton));\n        candidates.push_back(build_groups_sweep(ord_x));\n        candidates.push_back(build_groups_sweep(ord_y));\n        candidates.push_back(build_groups_sweep(ord_xy1));\n        candidates.push_back(build_groups_sweep(ord_xy2));\n\n        // grow variants\n        candidates.push_back(build_groups_grow(ord_morton, go_desc));\n        candidates.push_back(build_groups_grow(ord_morton, go_given));\n        candidates.push_back(build_groups_grow(ord_x, go_desc));\n        candidates.push_back(build_groups_grow(ord_y, go_desc));\n\n        // a few randomized grow runs (permute group order)\n        for (int t = 0; t < 3; t++) {\n            vector<int> go = go_desc;\n            shuffle(go.begin(), go.end(), rng);\n            candidates.push_back(build_groups_grow(ord_morton, go));\n        }\n\n        // Pick best candidate by estimated MST total length\n        long long bestScore = (1LL<<62);\n        int bestIdx = 0;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            long long sc = eval_groups(candidates[i]);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestIdx = i;\n            }\n        }\n        groups = move(candidates[bestIdx]);\n\n        // Build fallback MST edges/weights per group (once)\n        fallbackEdges.assign(M, {});\n        fallbackEdgesW.assign(M, {});\n        vector<long long> groupEstCost(M, 0);\n        for (int k = 0; k < M; k++) {\n            groupEstCost[k] = prim_build(groups[k], &fallbackEdges[k], &fallbackEdgesW[k]);\n        }\n\n        // --- Query planning ---\n        queryEdges.assign(M, {});\n        fullQueried.assign(M, false);\n        q_used = 0;\n\n        int reserve_for_large = Q / 2; // keep at least half for large groups\n        int small_query_limit = max(0, Q - reserve_for_large);\n\n        // small groups eligible for full query\n        vector<int> small;\n        for (int k = 0; k < M; k++) {\n            int s = (int)groups[k].size();\n            if (s >= 3 && s <= L) small.push_back(k);\n        }\n        sort(small.begin(), small.end(), [&](int a, int b){\n            int sa = (int)groups[a].size();\n            int sb = (int)groups[b].size();\n            if (sa != sb) return sa > sb;\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return a < b;\n        });\n\n        // Spend up to small_query_limit on small full queries (prefer larger ones)\n        for (int k : small) {\n            if (q_used >= small_query_limit) break;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        // Large groups: spend remaining queries on local neighborhoods around long estimated MST edges\n        vector<int> large;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) large.push_back(k);\n        sort(large.begin(), large.end(), [&](int a, int b){\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return (int)groups[a].size() > (int)groups[b].size();\n        });\n\n        for (int k : large) {\n            if (q_used >= Q) break;\n            int s = (int)groups[k].size();\n            int remaining = Q - q_used;\n\n            int targetQ = max(2, s / max(1, (L - 1))); // coverage-ish\n            targetQ = min(targetQ, 12);                // cap per group\n            targetQ = min(targetQ, remaining);\n\n            // sort fallback MST edges by descending weight to focus on long edges\n            auto edgesW = fallbackEdgesW[k];\n            sort(edgesW.begin(), edgesW.end(), [&](const EdgeW& A, const EdgeW& B){\n                return A.w > B.w;\n            });\n\n            // collect anchors from endpoints of top long edges\n            vector<int> anchors;\n            anchors.reserve(targetQ);\n            vector<char> inAnchor(N, false);\n\n            int takeEdges = min((int)edgesW.size(), targetQ * 2);\n            for (int i = 0; i < takeEdges && (int)anchors.size() < targetQ; i++) {\n                int a = edgesW[i].a, b = edgesW[i].b;\n                if (!inAnchor[a]) { inAnchor[a] = true; anchors.push_back(a); }\n                if ((int)anchors.size() >= targetQ) break;\n                if (!inAnchor[b]) { inAnchor[b] = true; anchors.push_back(b); }\n            }\n\n            // if still short, fill by evenly spaced nodes in Morton order within group\n            if ((int)anchors.size() < targetQ) {\n                vector<int> nodes = groups[k];\n                sort(nodes.begin(), nodes.end(), [&](int a, int b){\n                    if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n                    if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n                    return cities[a].cy < cities[b].cy;\n                });\n                for (int t = 0; t < (int)nodes.size() && (int)anchors.size() < targetQ; t += max(1, (int)nodes.size() / targetQ)) {\n                    int v = nodes[t];\n                    if (!inAnchor[v]) { inAnchor[v] = true; anchors.push_back(v); }\n                }\n            }\n\n            // perform local queries\n            for (int a : anchors) {\n                if (q_used >= Q) break;\n                auto subset = make_local_subset(k, a);\n                if ((int)subset.size() >= 3) {\n                    auto e = do_query(subset);\n                    queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                }\n            }\n        }\n\n        // If still have budget, query remaining small groups (not yet queried), still prefer larger\n        if (q_used < Q) {\n            for (int k : small) {\n                if (q_used >= Q) break;\n                if (fullQueried[k]) continue;\n                queryEdges[k] = do_query(groups[k]);\n                fullQueried[k] = true;\n            }\n        }\n\n        // --- Output final answer ---\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            // print cities of group\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            // print edges\n            auto edges = build_final_tree(k);\n            int need = (int)groups[k].size() - 1;\n            if ((int)edges.size() != need) {\n                // ultimate safety: fallback MST edges must be size-1 for size>=2\n                edges = fallbackEdges[k];\n                if ((int)edges.size() != need && need == 1) {\n                    int a = groups[k][0], b = groups[k][1];\n                    if (a > b) swap(a,b);\n                    edges = {{a,b}};\n                }\n            }\n            for (auto &e : edges) {\n                cout << e.first << \" \" << e.second << \"\\n\";\n            }\n        }\n        cout << flush;\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char a, d;\n};\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dirc[4] = {'U', 'D', 'L', 'R'};\nstatic const char actc[3] = {'M', 'S', 'A'};\n\nstruct Solver {\n    int N, M;\n    vector<pair<int,int>> P; // P[0]=start, P[1..M-1]=targets\n\n    // order in visit sequence, -1 if not a target/start\n    int ord[20][20];\n\n    // global blocks\n    uint8_t blockg[20][20]{};\n    int totalBlocks = 0;\n\n    vector<Action> answer;\n\n    // ---- parameters ----\n    static constexpr int KMAX = 13;                 // candidate toggle bits\n    static constexpr int MAX_BLOCKS = 120;          // soft safety cap\n    static constexpr int EXTRA_LOOKAHEAD = 2;       // allow +2 to invest\n\n    // Buffers for local BFS (max size for KMAX)\n    static constexpr int NN = 400;\n    static constexpr int MAX_STATES = NN * (1 << KMAX);\n\n    vector<int16_t> distBuf;       // -1 = unvisited\n    vector<int32_t> prevBuf;\n    vector<uint8_t> prevOpBuf;\n    vector<int> visitedStates;\n    vector<int> q;\n\n    Solver() {\n        distBuf.assign(MAX_STATES, -1);\n        prevBuf.resize(MAX_STATES);\n        prevOpBuf.resize(MAX_STATES);\n        visitedStates.reserve(1 << 20);\n        q.reserve(1 << 20);\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n    inline int posId(int x, int y) const { return x * N + y; }\n    inline pair<int,int> idPos(int id) const { return {id / N, id % N}; }\n\n    inline bool forbiddenCell(int x, int y, int curIndex) const {\n        // Forbid placing blocks on current or future targets (ord > curIndex).\n        // Past targets (ord <= curIndex) are allowed and useful as stoppers.\n        int t = ord[x][y];\n        return (t != -1 && t > curIndex);\n    }\n\n    // ---- Fixed-block BFS helpers (Move+Slide) ----\n    inline int slideStop(const uint8_t b[20][20], int x, int y, int dir) const {\n        int nx = x, ny = y;\n        while (true) {\n            int tx = nx + di[dir], ty = ny + dj[dir];\n            if (!inside(tx, ty)) break;\n            if (b[tx][ty]) break;\n            nx = tx; ny = ty;\n        }\n        return posId(nx, ny);\n    }\n\n    int shortestFixedLen(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S = posId(s.first, s.second);\n        int G = posId(g.first, g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> qq;\n        int head = 0, tail = 0;\n\n        dist[S] = 0;\n        qq[tail++] = S;\n\n        while (head < tail) {\n            int v = qq[head++];\n            if (v == G) return dist[v];\n            auto [x, y] = idPos(v);\n\n            for (int d = 0; d < 4; d++) {\n                // Move\n                int mx = x + di[d], my = y + dj[d];\n                if (inside(mx, my) && !b[mx][my]) {\n                    int to = posId(mx, my);\n                    if (dist[to] == -1) {\n                        dist[to] = dist[v] + 1;\n                        qq[tail++] = to;\n                    }\n                }\n                // Slide\n                int to = slideStop(b, x, y, d);\n                if (to != v && dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    qq[tail++] = to;\n                }\n            }\n        }\n        return 1e9; // unreachable (should be rare)\n    }\n\n    vector<Action> shortestFixedPath(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S = posId(s.first, s.second);\n        int G = posId(g.first, g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> prev;\n        prev.fill(-1);\n        array<uint8_t, NN> prevOp;\n        prevOp.fill(255);\n\n        array<int, NN> qq;\n        int head = 0, tail = 0;\n\n        dist[S] = 0;\n        qq[tail++] = S;\n\n        while (head < tail) {\n            int v = qq[head++];\n            if (v == G) break;\n            auto [x, y] = idPos(v);\n\n            for (int d = 0; d < 4; d++) {\n                // Move\n                int mx = x + di[d], my = y + dj[d];\n                if (inside(mx, my) && !b[mx][my]) {\n                    int to = posId(mx, my);\n                    if (dist[to] == -1) {\n                        dist[to] = dist[v] + 1;\n                        prev[to] = v;\n                        prevOp[to] = (0 * 4 + d);\n                        qq[tail++] = to;\n                    }\n                }\n                // Slide\n                int to = slideStop(b, x, y, d);\n                if (to != v && dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    prev[to] = v;\n                    prevOp[to] = (1 * 4 + d);\n                    qq[tail++] = to;\n                }\n            }\n        }\n\n        if (dist[G] == -1) return {};\n\n        vector<Action> res;\n        int cur = G;\n        while (cur != S) {\n            uint8_t code = prevOp[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prev[cur];\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    // ---- Local toggle BFS with lookahead selection ----\n    vector<Action> planLocalWithLookahead(\n        int curIndex, pair<int,int> s, pair<int,int> g,\n        int baselineLen, bool hasNext, pair<int,int> nxt,\n        int baselineObj, int &bestObjOut\n    ) {\n        bestObjOut = baselineObj;\n\n        // Small baselines: don't spend time.\n        if (baselineLen <= 1) return {};\n\n        // Candidate priorities\n        int pr[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) pr[i][j] = -1;\n\n        auto addCand = [&](int x, int y, int p) {\n            if (!inside(x, y)) return;\n            if (forbiddenCell(x, y, curIndex)) return; // forbid current/future targets\n            pr[x][y] = max(pr[x][y], p);\n        };\n\n        int sx = s.first, sy = s.second;\n        int gx = g.first, gy = g.second;\n\n        // Around goal (strong)\n        for (int d = 0; d < 4; d++) {\n            addCand(gx + di[d], gy + dj[d], 220);          // immediate stopper cells\n            addCand(gx + 2*di[d], gy + 2*dj[d], 160);      // slightly farther\n        }\n        for (int dx = -3; dx <= 3; dx++) for (int dy = -3; dy <= 3; dy++) {\n            if (abs(dx) + abs(dy) <= 3) addCand(gx + dx, gy + dy, 130);\n        }\n\n        // Around start\n        for (int d = 0; d < 4; d++) addCand(sx + di[d], sy + dj[d], 140);\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            if (abs(dx) + abs(dy) <= 2) addCand(sx + dx, sy + dy, 90);\n        }\n\n        // L-shape corners (good turning points)\n        int c1x = sx, c1y = gy;\n        int c2x = gx, c2y = sy;\n        for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {\n            addCand(c1x + dx, c1y + dy, 120);\n            addCand(c2x + dx, c2y + dy, 120);\n        }\n\n        // Same row/col near goal (potential stoppers)\n        for (int t = 1; t <= 3; t++) {\n            addCand(gx, gy + t, 80);\n            addCand(gx, gy - t, 80);\n            addCand(gx + t, gy, 80);\n            addCand(gx - t, gy, 80);\n        }\n\n        // Existing blocks near start/goal (allow removing)\n        for (int dx = -3; dx <= 3; dx++) for (int dy = -3; dy <= 3; dy++) {\n            int x = gx + dx, y = gy + dy;\n            if (inside(x,y) && blockg[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x, y, 125);\n        }\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            int x = sx + dx, y = sy + dy;\n            if (inside(x,y) && blockg[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x, y, 95);\n        }\n\n        // If we have a next target, prep around it slightly (investment)\n        if (hasNext) {\n            int nx = nxt.first, ny = nxt.second;\n            for (int d = 0; d < 4; d++) addCand(nx + di[d], ny + dj[d], 70);\n            for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n                if (abs(dx) + abs(dy) <= 2) addCand(nx + dx, ny + dy, 45);\n            }\n        }\n\n        struct C { int p,x,y; };\n        vector<C> cand;\n        cand.reserve(200);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (pr[i][j] >= 0) cand.push_back({pr[i][j], i, j});\n        }\n        if (cand.empty()) return {};\n\n        sort(cand.begin(), cand.end(), [&](const C& a, const C& b){\n            if (a.p != b.p) return a.p > b.p;\n            // tie-break: closer to (start+goal)/2 a bit\n            int mx = (sx + gx) / 2, my = (sy + gy) / 2;\n            int da = abs(a.x - mx) + abs(a.y - my);\n            int db = abs(b.x - mx) + abs(b.y - my);\n            if (da != db) return da < db;\n            if (a.x != b.x) return a.x < b.x;\n            return a.y < b.y;\n        });\n\n        int K = min((int)cand.size(), KMAX);\n        cand.resize(K);\n        int MSZ = 1 << K;\n\n        int idx[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) idx[i][j] = -1;\n        for (int t = 0; t < K; t++) idx[cand[t].x][cand[t].y] = t;\n\n        // init mask\n        int initMask = 0;\n        for (int t = 0; t < K; t++) {\n            if (blockg[cand[t].x][cand[t].y]) initMask |= (1 << t);\n        }\n        int baseBlocks = totalBlocks - __builtin_popcount((unsigned)initMask);\n\n        auto sid = [&](int mask, int pos) { return mask * NN + pos; };\n\n        auto isBlocked = [&](int x, int y, int mask) -> bool {\n            if (!inside(x, y)) return true;\n            int t = idx[x][y];\n            if (t >= 0) return (mask >> t) & 1;\n            return blockg[x][y];\n        };\n\n        auto slideStopMask = [&](int x, int y, int dir, int mask) -> int {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[dir], ty = ny + dj[dir];\n                if (!inside(tx, ty)) break;\n                if (isBlocked(tx, ty, mask)) break;\n                nx = tx; ny = ty;\n            }\n            return posId(nx, ny);\n        };\n\n        int Spos = posId(s.first, s.second);\n        int Gpos = posId(g.first, g.second);\n\n        int limit = baselineLen + (hasNext ? EXTRA_LOOKAHEAD : 0);\n\n        // BFS init\n        visitedStates.clear();\n        q.clear();\n\n        auto pushState = [&](int id, int16_t d, int32_t parent, uint8_t op) {\n            distBuf[id] = d;\n            prevBuf[id] = parent;\n            prevOpBuf[id] = op;\n            visitedStates.push_back(id);\n            q.push_back(id);\n        };\n\n        int s0 = sid(initMask, Spos);\n        pushState(s0, 0, -1, 255);\n\n        // BFS\n        size_t head = 0;\n        while (head < q.size()) {\n            int v = q[head++];\n            int16_t dcur = distBuf[v];\n            if (dcur >= limit) continue;\n\n            int mask = v / NN;\n            int pos  = v % NN;\n            auto [x, y] = idPos(pos);\n\n            // Move/Slide\n            for (int dd = 0; dd < 4; dd++) {\n                // Move\n                int mx = x + di[dd], my = y + dj[dd];\n                if (inside(mx, my) && !isBlocked(mx, my, mask)) {\n                    int to = sid(mask, posId(mx, my));\n                    if (distBuf[to] == -1) pushState(to, dcur + 1, v, (0 * 4 + dd));\n                }\n                // Slide\n                int spos = slideStopMask(x, y, dd, mask);\n                if (spos != pos) {\n                    int to = sid(mask, spos);\n                    if (distBuf[to] == -1) pushState(to, dcur + 1, v, (1 * 4 + dd));\n                }\n            }\n\n            // Alter adjacent candidate only\n            for (int dd = 0; dd < 4; dd++) {\n                int ax = x + di[dd], ay = y + dj[dd];\n                if (!inside(ax, ay)) continue;\n                int t = idx[ax][ay];\n                if (t < 0) continue;\n                if (forbiddenCell(ax, ay, curIndex)) continue; // safety\n\n                int nmask = mask ^ (1 << t);\n                if (baseBlocks + __builtin_popcount((unsigned)nmask) > MAX_BLOCKS) continue;\n\n                int to = sid(nmask, pos);\n                if (distBuf[to] == -1) pushState(to, dcur + 1, v, (2 * 4 + dd));\n            }\n        }\n\n        // Collect reachable goal states within limit\n        struct GS { int id; int16_t d; };\n        vector<GS> goals;\n        goals.reserve(MSZ);\n\n        for (int mask = 0; mask < MSZ; mask++) {\n            int id = sid(mask, Gpos);\n            int16_t d = distBuf[id];\n            if (d != -1 && d <= limit) goals.push_back({id, d});\n        }\n        if (goals.empty()) {\n            for (int id : visitedStates) distBuf[id] = -1;\n            return {};\n        }\n\n        sort(goals.begin(), goals.end(), [](const GS& a, const GS& b){\n            if (a.d != b.d) return a.d < b.d;\n            return a.id < b.id;\n        });\n        if ((int)goals.size() > 32) goals.resize(32);\n\n        // Evaluate with lookahead\n        int bestState = goals[0].id;\n        int bestObj = 1e9;\n        int bestD1 = 1e9;\n        int bestPop = 1e9;\n\n        uint8_t temp[20][20];\n\n        for (auto &gs : goals) {\n            int id = gs.id;\n            int16_t d1 = gs.d;\n            int mask = id / NN;\n\n            // build temp blocks\n            for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) temp[i][j] = blockg[i][j];\n            for (int t = 0; t < K; t++) {\n                temp[cand[t].x][cand[t].y] = (mask >> t) & 1;\n            }\n\n            int d2 = 0;\n            if (hasNext) d2 = shortestFixedLen(temp, g, nxt);\n\n            int obj = (int)d1 + d2;\n            int pop = __builtin_popcount((unsigned)mask);\n\n            if (obj < bestObj ||\n                (obj == bestObj && d1 < bestD1) ||\n                (obj == bestObj && d1 == bestD1 && pop < bestPop)) {\n                bestObj = obj;\n                bestD1 = d1;\n                bestPop = pop;\n                bestState = id;\n            }\n        }\n\n        bestObjOut = bestObj;\n\n        // Reconstruct bestState path\n        vector<Action> res;\n        int cur = bestState;\n        while (cur != s0) {\n            uint8_t code = prevOpBuf[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prevBuf[cur];\n            if (cur < 0) break; // safety\n        }\n        reverse(res.begin(), res.end());\n\n        // reset dist buffer\n        for (int id : visitedStates) distBuf[id] = -1;\n\n        return res;\n    }\n\n    // ---- Apply action to global state ----\n    void applyAction(pair<int,int>& cur, const Action& ac) {\n        int d = 0;\n        while (d < 4 && dirc[d] != ac.d) d++;\n        int x = cur.first, y = cur.second;\n\n        if (ac.a == 'M') {\n            cur = {x + di[d], y + dj[d]};\n        } else if (ac.a == 'S') {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[d], ty = ny + dj[d];\n                if (!inside(tx, ty)) break;\n                if (blockg[tx][ty]) break;\n                nx = tx; ny = ty;\n            }\n            cur = {nx, ny};\n        } else { // 'A'\n            int ax = x + di[d], ay = y + dj[d];\n            bool before = blockg[ax][ay];\n            blockg[ax][ay] = !blockg[ax][ay];\n            if (!before && blockg[ax][ay]) totalBlocks++;\n            if (before && !blockg[ax][ay]) totalBlocks--;\n        }\n    }\n\n    void solve() {\n        pair<int,int> cur = P[0];\n\n        for (int k = 0; k < M - 1; k++) {\n            pair<int,int> goal = P[k + 1];\n            bool hasNext = (k + 2 < M);\n            pair<int,int> nxt = hasNext ? P[k + 2] : make_pair(-1, -1);\n\n            // Baseline shortest with current blocks (Move+Slide)\n            vector<Action> base = shortestFixedPath(blockg, cur, goal);\n            if (base.empty()) {\n                // extremely rare; as a fallback, do nothing (will likely fail gracefully)\n                // but public tests should not hit this\n                base.clear();\n            }\n            int baseLen = (int)base.size();\n            int baseNextLen = hasNext ? shortestFixedLen(blockg, goal, nxt) : 0;\n            int baseObj = baseLen + baseNextLen;\n\n            // Local plan with toggles and lookahead selection\n            int localObj = baseObj;\n            vector<Action> local = planLocalWithLookahead(\n                k, cur, goal, baseLen, hasNext, nxt, baseObj, localObj\n            );\n\n            bool useLocal = false;\n            if (!local.empty()) {\n                if (localObj < baseObj) useLocal = true;\n                else if (localObj == baseObj && (int)local.size() < baseLen) useLocal = true;\n            }\n\n            const vector<Action>& use = useLocal ? local : base;\n\n            for (auto &ac : use) {\n                if ((int)answer.size() >= 2 * N * M) break;\n                answer.push_back(ac);\n                applyAction(cur, ac);\n            }\n\n            // Safety: if somehow not at goal, force with baseline (rare)\n            if (cur != goal && (int)answer.size() < 2 * N * M) {\n                vector<Action> fb = shortestFixedPath(blockg, cur, goal);\n                for (auto &ac : fb) {\n                    if ((int)answer.size() >= 2 * N * M) break;\n                    answer.push_back(ac);\n                    applyAction(cur, ac);\n                }\n            }\n\n            if ((int)answer.size() >= 2 * N * M) break;\n        }\n\n        for (auto &ac : answer) {\n            cout << ac.a << ' ' << ac.d << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    cin >> s.N >> s.M;\n    s.P.resize(s.M);\n\n    for (int i = 0; i < 20; i++) for (int j = 0; j < 20; j++) s.ord[i][j] = -1;\n\n    for (int k = 0; k < s.M; k++) {\n        int x, y;\n        cin >> x >> y;\n        s.P[k] = {x, y};\n        s.ord[x][y] = k;\n    }\n\n    s.solve();\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect { int a,b,c,d; }; // [a,c) x [b,d)\n\nstatic inline bool overlap1D(int l1,int r1,int l2,int r2){\n    return max(l1,l2) < min(r1,r2);\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now()-st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32(){ return (uint32_t)next_u64(); }\n    int rand_int(int l,int r){\n        if(l>r) return l;\n        uint64_t range=(uint64_t)(r-l+1);\n        return l + (int)(next_u64()%range);\n    }\n    double rand01(){\n        return (next_u64()>>11) * (1.0/9007199254740992.0);\n    }\n};\n\nstruct BlockInfo {\n    int j;          // nearest blocker index\n    int otherCoord; // second blocker coordinate or boundary\n};\n\nstruct Solver {\n    int n;\n    vector<int> x,y;\n    vector<long long> r;\n    vector<Rect> rect;\n    vector<double> p;\n    double sumP=0.0;\n\n    SplitMix64 rng;\n    Timer timer;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin>>n;\n        x.resize(n); y.resize(n); r.resize(n);\n        for(int i=0;i<n;i++) cin>>x[i]>>y[i]>>r[i];\n\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = SplitMix64(seed);\n\n        rect.resize(n);\n        for(int i=0;i<n;i++) rect[i]={x[i],y[i],x[i]+1,y[i]+1};\n\n        p.assign(n,0.0);\n        recompute_all_scores();\n    }\n\n    inline long long area(const Rect& R) const {\n        return 1LL*(R.c-R.a)*(R.d-R.b);\n    }\n    inline bool contains_point(int i,const Rect& R) const {\n        return (R.a<=x[i] && x[i]<R.c && R.b<=y[i] && y[i]<R.d);\n    }\n    inline double satisfaction(int i,const Rect& R) const {\n        if(!contains_point(i,R)) return 0.0;\n        long long s=area(R), ri=r[i];\n        long long mn=min(ri,s), mx=max(ri,s);\n        double ratio = (double)mn/(double)mx;\n        double t = 1.0 - ratio;\n        return 1.0 - t*t;\n    }\n\n    void recompute_all_scores(){\n        sumP=0.0;\n        for(int i=0;i<n;i++){\n            p[i]=satisfaction(i,rect[i]);\n            sumP+=p[i];\n        }\n    }\n\n    // pick index with worst (smallest) p among k random candidates\n    inline int pick_bad_rect(int k=4){\n        int best = (int)(rng.next_u32()%n);\n        double bestScore = p[best]; // smaller is worse\n        for(int t=1;t<k;t++){\n            int i = (int)(rng.next_u32()%n);\n            if(p[i] < bestScore){\n                bestScore = p[i];\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    // ===== single-side move =====\n    // dir: 0=a(left),1=c(right),2=b(down),3=d(up)\n    bool feasible_range(int i,int dir,int &low,int &high) const {\n        const Rect &R=rect[i];\n        if(dir==0 || dir==1){\n            int leftLimit=0, rightLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q=rect[j];\n                if(!overlap1D(R.b,R.d,Q.b,Q.d)) continue;\n                if(Q.c<=R.a) leftLimit=max(leftLimit,Q.c);\n                if(R.c<=Q.a) rightLimit=min(rightLimit,Q.a);\n            }\n            if(dir==0){\n                low=leftLimit;\n                high=min(x[i], R.c-1);\n            }else{\n                low=max(x[i]+1, R.a+1);\n                high=rightLimit;\n            }\n        }else{\n            int downLimit=0, upLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q=rect[j];\n                if(!overlap1D(R.a,R.c,Q.a,Q.c)) continue;\n                if(Q.d<=R.b) downLimit=max(downLimit,Q.d);\n                if(R.d<=Q.b) upLimit=min(upLimit,Q.b);\n            }\n            if(dir==2){\n                low=downLimit;\n                high=min(y[i], R.d-1);\n            }else{\n                low=max(y[i]+1, R.b+1);\n                high=upLimit;\n            }\n        }\n        return low<=high;\n    }\n\n    int desired_side_value(int i,int dir,int low,int high) const {\n        const Rect& R=rect[i];\n        long long ri=r[i];\n        if(dir==0 || dir==1){\n            int h=R.d-R.b;\n            long long desiredW=(ri + h/2)/h;\n            desiredW=max<long long>(1, min<long long>(10000, desiredW));\n            if(dir==0){\n                long long desA=(long long)R.c - desiredW;\n                return (int)max<long long>(low, min<long long>(high, desA));\n            }else{\n                long long desC=(long long)R.a + desiredW;\n                return (int)max<long long>(low, min<long long>(high, desC));\n            }\n        }else{\n            int w=R.c-R.a;\n            long long desiredH=(ri + w/2)/w;\n            desiredH=max<long long>(1, min<long long>(10000, desiredH));\n            if(dir==2){\n                long long desB=(long long)R.d - desiredH;\n                return (int)max<long long>(low, min<long long>(high, desB));\n            }else{\n                long long desD=(long long)R.b + desiredH;\n                return (int)max<long long>(low, min<long long>(high, desD));\n            }\n        }\n    }\n\n    static inline Rect with_side(Rect R,int dir,int val){\n        if(dir==0) R.a=val;\n        else if(dir==1) R.c=val;\n        else if(dir==2) R.b=val;\n        else R.d=val;\n        return R;\n    }\n\n    bool greedy_improve_one_side(int i){\n        double cur=p[i];\n        double best=cur;\n        Rect bestR=rect[i];\n\n        for(int dir=0;dir<4;dir++){\n            int low,high;\n            if(!feasible_range(i,dir,low,high)) continue;\n            int curVal = (dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n            if(low==high && low==curVal) continue;\n\n            int des=desired_side_value(i,dir,low,high);\n            int cand[3]={des,low,high};\n            for(int v: cand){\n                if(v<low||v>high||v==curVal) continue;\n                Rect R2=with_side(rect[i],dir,v);\n                if(R2.a>=R2.c || R2.b>=R2.d) continue;\n                double sc=satisfaction(i,R2);\n                if(sc>best+1e-12){\n                    best=sc; bestR=R2;\n                }\n            }\n        }\n        if(best>cur+1e-12){\n            rect[i]=bestR;\n            sumP += (best - p[i]);\n            p[i]=best;\n            return true;\n        }\n        return false;\n    }\n\n    // ===== push move (area stealing), 1 scan gives nearest+second blocker =====\n    BlockInfo blocker_info(int i,int dir) const {\n        const Rect &I=rect[i];\n        if(dir==1){ // right: min a>=I.c\n            int min1=10001, min2=10001, idx=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ak=R.a;\n                if(ak>=I.c){\n                    if(ak<min1){ min2=min1; min1=ak; idx=k; }\n                    else if(ak<min2){ min2=ak; }\n                }\n            }\n            return {idx, (min2==10001?10000:min2)};\n        }else if(dir==0){ // left: max c<=I.a\n            int max1=-1, max2=-1, idx=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ck=R.c;\n                if(ck<=I.a){\n                    if(ck>max1){ max2=max1; max1=ck; idx=k; }\n                    else if(ck>max2){ max2=ck; }\n                }\n            }\n            return {idx, (max2==-1?0:max2)};\n        }else if(dir==3){ // up: min b>=I.d\n            int min1=10001, min2=10001, idx=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n                int bk=R.b;\n                if(bk>=I.d){\n                    if(bk<min1){ min2=min1; min1=bk; idx=k; }\n                    else if(bk<min2){ min2=bk; }\n                }\n            }\n            return {idx, (min2==10001?10000:min2)};\n        }else{ // down: max d<=I.b\n            int max1=-1, max2=-1, idx=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n                int dk=R.d;\n                if(dk<=I.b){\n                    if(dk>max1){ max2=max1; max1=dk; idx=k; }\n                    else if(dk>max2){ max2=dk; }\n                }\n            }\n            return {idx, (max2==-1?0:max2)};\n        }\n    }\n\n    int push_dmax(int i,int dir,const BlockInfo& bi) const {\n        int j=bi.j;\n        if(j<0) return 0;\n        const Rect &I=rect[i];\n        const Rect &J=rect[j];\n\n        int maxShrink=0, maxExpand=0;\n        if(dir==1){\n            maxShrink = min(x[j], J.c-1) - J.a;\n            maxShrink = min(maxShrink, (J.c-J.a)-1);\n            maxExpand = min(10000 - I.c, bi.otherCoord - I.c);\n        }else if(dir==0){\n            int minC = max(x[j]+1, J.a+1);\n            maxShrink = J.c - minC;\n            maxShrink = min(maxShrink, (J.c-J.a)-1);\n            maxExpand = min(I.a, I.a - bi.otherCoord);\n        }else if(dir==3){\n            maxShrink = min(y[j], J.d-1) - J.b;\n            maxShrink = min(maxShrink, (J.d-J.b)-1);\n            maxExpand = min(10000 - I.d, bi.otherCoord - I.d);\n        }else{\n            int minD = max(y[j]+1, J.b+1);\n            maxShrink = J.d - minD;\n            maxShrink = min(maxShrink, (J.d-J.b)-1);\n            maxExpand = min(I.b, I.b - bi.otherCoord);\n        }\n        if(maxShrink<0) maxShrink=0;\n        if(maxExpand<0) maxExpand=0;\n        return min(maxShrink, maxExpand);\n    }\n\n    inline void apply_push(int i,int dir,int j,int delta){\n        if(dir==1){ rect[i].c += delta; rect[j].a += delta; }\n        else if(dir==0){ rect[i].a -= delta; rect[j].c -= delta; }\n        else if(dir==3){ rect[i].d += delta; rect[j].b += delta; }\n        else { rect[i].b -= delta; rect[j].d -= delta; }\n    }\n\n    bool greedy_improve_push(int i){\n        double bestGain = 0.0;\n        int bestDir=-1, bestJ=-1, bestDelta=0;\n\n        for(int dir=0;dir<4;dir++){\n            BlockInfo bi = blocker_info(i,dir);\n            int j=bi.j;\n            if(j<0) continue;\n            int dmax = push_dmax(i,dir,bi);\n            if(dmax<=0) continue;\n\n            int cand[3];\n            cand[0]=1;\n            cand[1]=dmax;\n            long long ai = area(rect[i]);\n            long long deficit = r[i] - ai;\n            long long per = (dir==0||dir==1) ? (rect[i].d-rect[i].b) : (rect[i].c-rect[i].a);\n            int desd = 1;\n            if(deficit>0) desd = (int)min<long long>(dmax, max<long long>(1, (deficit + per - 1)/per));\n            cand[2]=desd;\n\n            for(int t=0;t<3;t++){\n                int delta=cand[t];\n                if(delta<1 || delta>dmax) continue;\n\n                Rect oldI=rect[i], oldJ=rect[j];\n                double oldPi=p[i], oldPj=p[j];\n\n                apply_push(i,dir,j,delta);\n                double newPi=satisfaction(i,rect[i]);\n                double newPj=satisfaction(j,rect[j]);\n                double gain=(newPi+newPj)-(oldPi+oldPj);\n\n                rect[i]=oldI; rect[j]=oldJ;\n                if(gain>bestGain+1e-12){\n                    bestGain=gain;\n                    bestDir=dir; bestJ=j; bestDelta=delta;\n                }\n            }\n        }\n\n        if(bestGain>1e-12){\n            double oldPi=p[i], oldPj=p[bestJ];\n            apply_push(i,bestDir,bestJ,bestDelta);\n            double newPi=satisfaction(i,rect[i]);\n            double newPj=satisfaction(bestJ,rect[bestJ]);\n            p[i]=newPi; p[bestJ]=newPj;\n            sumP += (newPi-oldPi) + (newPj-oldPj);\n            return true;\n        }\n        return false;\n    }\n\n    inline bool greedy_step(int i){\n        bool a=greedy_improve_one_side(i);\n        bool b=greedy_improve_push(i);\n        return a||b;\n    }\n\n    void greedy_init(){\n        vector<int> order(n);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a,int b){ return r[a]>r[b]; });\n\n        for(int pass=0; pass<18; pass++){\n            bool any=false;\n            for(int idx=0; idx<n; idx++){\n                int i=order[idx];\n                for(int rep=0; rep<3; rep++){\n                    if(!greedy_step(i)) break;\n                    any=true;\n                }\n            }\n            if(!any) break;\n        }\n\n        // targeted polishing: pick bad rectangles more often\n        for(int it=0; it<12000; it++){\n            int i = pick_bad_rect(4);\n            greedy_step(i);\n        }\n    }\n\n    void simulated_annealing(double timeLimitSec){\n        vector<Rect> bestRect = rect;\n        vector<double> bestP = p;\n        double bestSum = sumP;\n\n        const double T0=0.16, T1=0.0025;\n        long long iters=0;\n        double T=T0;\n\n        while(true){\n            if((iters & 4095) == 0){\n                double t = timer.elapsed();\n                if(t >= timeLimitSec) break;\n                double prog = t / timeLimitSec;\n                T = T0 * exp(log(T1/T0) * prog);\n            }\n            iters++;\n\n            int i = pick_bad_rect(4);\n            bool doPush = (rng.rand01() < 0.38);\n\n            if(!doPush){\n                // choose better of two random dirs (less wasted scans)\n                int dir1 = (int)(rng.next_u32() & 3);\n                int dir2 = (int)(rng.next_u32() & 3);\n                int low1,high1, low2,high2;\n                bool ok1 = feasible_range(i,dir1,low1,high1);\n                bool ok2 = feasible_range(i,dir2,low2,high2);\n                int dir = -1, low=0, high=0;\n                if(ok1 && ok2){\n                    int span1 = high1-low1, span2 = high2-low2;\n                    if(span2 > span1){ dir=dir2; low=low2; high=high2; }\n                    else { dir=dir1; low=low1; high=high1; }\n                }else if(ok1){\n                    dir=dir1; low=low1; high=high1;\n                }else if(ok2){\n                    dir=dir2; low=low2; high=high2;\n                }else continue;\n\n                int curVal = (dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n                if(low==high) continue;\n\n                int des = desired_side_value(i,dir,low,high);\n                int candVal;\n                if(rng.rand01() < 0.78){\n                    int span = max(1, (high-low)/8);\n                    candVal = des + rng.rand_int(-span, span);\n                    candVal = max(low, min(high, candVal));\n                }else{\n                    candVal = rng.rand_int(low, high);\n                }\n                if(candVal==curVal) continue;\n\n                Rect oldR=rect[i];\n                double oldPi=p[i];\n\n                Rect newR = with_side(oldR,dir,candVal);\n                if(newR.a>=newR.c || newR.b>=newR.d) continue;\n\n                double newPi=satisfaction(i,newR);\n                double diff=newPi-oldPi;\n\n                bool accept = (diff>=0) || (rng.rand01() < exp(diff / T));\n                if(accept){\n                    rect[i]=newR;\n                    p[i]=newPi;\n                    sumP+=diff;\n                    if(sumP>bestSum+1e-12){\n                        bestSum=sumP;\n                        bestRect=rect;\n                        bestP=p;\n                    }\n                }\n            }else{\n                // push: choose better of two random dirs by dmax\n                int dirA = (int)(rng.next_u32() & 3);\n                int dirB = (int)(rng.next_u32() & 3);\n\n                BlockInfo biA = blocker_info(i,dirA);\n                int dmaxA = push_dmax(i,dirA,biA);\n\n                BlockInfo biB = blocker_info(i,dirB);\n                int dmaxB = push_dmax(i,dirB,biB);\n\n                int dir, dmax;\n                BlockInfo bi;\n                if(dmaxB > dmaxA){ dir=dirB; dmax=dmaxB; bi=biB; }\n                else { dir=dirA; dmax=dmaxA; bi=biA; }\n\n                int j=bi.j;\n                if(j<0 || dmax<=0) continue;\n\n                int delta;\n                if(rng.rand01() < 0.80){\n                    long long ai=area(rect[i]);\n                    long long deficit=r[i]-ai;\n                    long long per=(dir==0||dir==1)?(rect[i].d-rect[i].b):(rect[i].c-rect[i].a);\n                    int desd=1;\n                    if(deficit>0) desd=(int)min<long long>(dmax, max<long long>(1, (deficit + per - 1)/per));\n                    int span=max(1, dmax/10);\n                    delta = desd + rng.rand_int(-span, span);\n                    delta = max(1, min(dmax, delta));\n                }else{\n                    delta = rng.rand_int(1, dmax);\n                }\n\n                Rect oldI=rect[i], oldJ=rect[j];\n                double oldPi=p[i], oldPj=p[j];\n\n                apply_push(i,dir,j,delta);\n                double newPi=satisfaction(i,rect[i]);\n                double newPj=satisfaction(j,rect[j]);\n                double diff=(newPi+newPj)-(oldPi+oldPj);\n\n                bool accept = (diff>=0) || (rng.rand01() < exp(diff / T));\n                if(accept){\n                    p[i]=newPi; p[j]=newPj;\n                    sumP+=diff;\n                    if(sumP>bestSum+1e-12){\n                        bestSum=sumP;\n                        bestRect=rect;\n                        bestP=p;\n                    }\n                }else{\n                    rect[i]=oldI; rect[j]=oldJ;\n                }\n            }\n        }\n\n        rect=bestRect;\n        p=bestP;\n        sumP=bestSum;\n    }\n\n    void targeted_final_polish(int steps){\n        for(int it=0; it<steps; it++){\n            int i = pick_bad_rect(6);\n            greedy_step(i);\n        }\n    }\n\n    void solve(){\n        const double HARD_LIMIT = 4.82; // safe margin\n\n        greedy_init();\n\n        if(timer.elapsed() < HARD_LIMIT - 0.05){\n            simulated_annealing(HARD_LIMIT);\n        }\n\n        // if some time remains, do a small targeted greedy finish\n        double t = timer.elapsed();\n        if(t < 4.90){ // very cheap, still safe\n            int extra = (t < 4.70 ? 12000 : 6000);\n            targeted_final_polish(extra);\n        }\n\n        for(int i=0;i<n;i++){\n            cout<<rect[i].a<<' '<<rect[i].b<<' '<<rect[i].c<<' '<<rect[i].d<<\"\\n\";\n        }\n    }\n};\n\nint main(){\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50, W = 50, N = H * W;\nstatic constexpr int MAXM = 2500;\nstatic constexpr int BSZ = (MAXM + 63) / 64;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463325252ULL) {}\n    inline uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); } // inclusive\n};\n\nstruct TileSet {\n    array<uint64_t, BSZ> b{};\n    inline void clear() { b.fill(0); }\n    inline bool test(int i) const { return (b[i >> 6] >> (i & 63)) & 1ULL; }\n    inline void set1(int i) { b[i >> 6] |= (1ULL << (i & 63)); }\n    inline void reset1(int i) { b[i >> 6] &= ~(1ULL << (i & 63)); }\n};\n\nstruct State {\n    vector<int> path;      // squares\n    vector<int> tileStack; // tile ids (parallel to path)\n    TileSet used;\n    int score = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    cin >> si >> sj;\n    const int start = si * W + sj;\n\n    vector<int> tile(N);\n    int maxTile = 0;\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int t; cin >> t;\n        tile[i * W + j] = t;\n        maxTile = max(maxTile, t);\n    }\n    const int M = maxTile + 1;\n\n    vector<int> val(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int p; cin >> p;\n        val[i * W + j] = p;\n    }\n\n    // Square adjacency excluding same-tile moves\n    array<array<int, 4>, N> nbr;\n    array<uint8_t, N> deg{};\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        uint8_t d = 0;\n        auto add = [&](int ni, int nj) {\n            if (ni < 0 || ni >= H || nj < 0 || nj >= W) return;\n            int v = ni * W + nj;\n            if (tile[u] == tile[v]) return;\n            nbr[u][d++] = v;\n        };\n        add(i - 1, j); add(i + 1, j); add(i, j - 1); add(i, j + 1);\n        deg[u] = d;\n    }\n\n    // Tile adjacency graph (unique)\n    vector<vector<int>> tadj(M);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        int tu = tile[u];\n        if (j + 1 < W) {\n            int v = i * W + (j + 1);\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n        if (i + 1 < H) {\n            int v = (i + 1) * W + j;\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n    }\n    for (int t = 0; t < M; t++) {\n        auto &v = tadj[t];\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n    }\n\n    auto deg_square = [&](int sq, const TileSet &used) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            if (!used.test(tile[to])) d++;\n        }\n        return d;\n    };\n    auto deg_square_forbid_tile = [&](int sq, const TileSet &used, int forbidTile) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            int tt = tile[to];\n            if (tt == forbidTile) continue;\n            if (!used.test(tt)) d++;\n        }\n        return d;\n    };\n    auto deg_tile_unvisited = [&](int t, const TileSet &used) -> int {\n        int d = 0;\n        for (int nx : tadj[t]) if (!used.test(nx)) d++;\n        return d;\n    };\n    auto deg_tile_unvisited_forbid = [&](int t, const TileSet &used, int forbidTile) -> int {\n        int d = 0;\n        for (int nx : tadj[t]) if (nx != forbidTile && !used.test(nx)) d++;\n        return d;\n    };\n\n    auto extend_greedy = [&](State &st, XorShift64 &rng,\n                            double a1, double a2, double g, double deadPenalty) {\n        while (true) {\n            int cur = st.path.back();\n\n            int cand[4];\n            int cm = 0;\n            for (int k = 0; k < (int)deg[cur]; k++) {\n                int to = nbr[cur][k];\n                if (!st.used.test(tile[to])) cand[cm++] = to;\n            }\n            if (cm == 0) break;\n\n            // avoid picking dead-end if there exists a non-dead-end move\n            int d1[4];\n            bool anyNonDead = false;\n            for (int i = 0; i < cm; i++) {\n                d1[i] = deg_square(cand[i], st.used);\n                if (d1[i] > 0) anyNonDead = true;\n            }\n\n            struct Item { int sq; double sc; };\n            Item items[4];\n            int im = 0;\n\n            for (int i = 0; i < cm; i++) {\n                int nx = cand[i];\n                int dn1 = d1[i];\n                if (anyNonDead && dn1 == 0) continue;\n\n                int tn = tile[nx];\n                int dt = deg_tile_unvisited(tn, st.used);\n\n                // 2-step lookahead best2\n                double best2 = 0.0;\n                for (int k = 0; k < (int)deg[nx]; k++) {\n                    int nn = nbr[nx][k];\n                    int tnn = tile[nn];\n                    if (st.used.test(tnn)) continue;\n                    int d2 = deg_square_forbid_tile(nn, st.used, tn);\n                    int dt2 = deg_tile_unvisited_forbid(tnn, st.used, tn);\n                    double s2 = val[nn] + a1 * d2 + 0.5 * a2 * dt2;\n                    if (s2 > best2) best2 = s2;\n                }\n\n                double sc = 0.0;\n                sc += val[nx];\n                sc += a1 * dn1;\n                sc += a2 * dt;\n                sc += g * best2;\n                if (dn1 == 0) sc -= deadPenalty;\n                sc += rng.next_double() * 1e-3;\n\n                items[im++] = {nx, sc};\n            }\n\n            if (im == 0) break;\n\n            // sort desc (im<=4)\n            for (int i = 0; i < im; i++) {\n                int best = i;\n                for (int j = i + 1; j < im; j++) if (items[j].sc > items[best].sc) best = j;\n                swap(items[i], items[best]);\n            }\n\n            int pick = 0;\n            double u = rng.next_double();\n            if (im >= 2) {\n                if (u < 0.80) pick = 0;\n                else if (u < 0.95) pick = 1;\n                else pick = min(2, im - 1);\n            }\n\n            int nxt = items[pick].sq;\n            int tnx = tile[nxt];\n            st.used.set1(tnx);\n            st.path.push_back(nxt);\n            st.tileStack.push_back(tnx);\n            st.score += val[nxt];\n        }\n    };\n\n    auto build_one = [&](XorShift64 &rng) -> State {\n        State st;\n        st.used.clear();\n        st.path.reserve(N);\n        st.tileStack.reserve(N);\n\n        st.path.push_back(start);\n        st.tileStack.push_back(tile[start]);\n        st.used.set1(tile[start]);\n        st.score = val[start];\n\n        // parameters biased to \"survive long\"\n        double a1 = 6.0 + 22.0 * rng.next_double();   // square-degree weight\n        double a2 = 1.5 + 10.0 * rng.next_double();   // tile-degree weight\n        double g  = 0.10 + 0.55 * rng.next_double();  // lookahead\n        double dp = 25.0 + 45.0 * rng.next_double();  // dead-end penalty\n\n        extend_greedy(st, rng, a1, a2, g, dp);\n        return st;\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto now = [&]() { return chrono::steady_clock::now(); };\n    const double TL = 1.95;\n\n    XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multi-start for initial best\n    State best = build_one(rng);\n    while (chrono::duration<double>(now() - t0).count() < 0.35) {\n        State s = build_one(rng);\n        if (s.score > best.score) best = std::move(s);\n    }\n\n    State cur = best;\n\n    // SA with fast cut&undo\n    vector<int> removedSq, removedTile;\n    removedSq.reserve(N);\n    removedTile.reserve(N);\n\n    int it = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > TL) break;\n        it++;\n\n        if (it % 2500 == 0) cur = best;\n\n        int L = (int)cur.path.size();\n        if (L <= 1) continue;\n\n        int k;\n        double r = rng.next_double();\n        if (r < 0.70) {\n            int lo = max(0, L - 1 - 220);\n            k = rng.next_int(lo, L - 2);\n        } else if (r < 0.92) {\n            int lo = max(0, L - 1 - 600);\n            k = rng.next_int(lo, L - 2);\n        } else {\n            k = rng.next_int(0, L - 2);\n        }\n\n        int origScore = cur.score;\n\n        removedSq.clear();\n        removedTile.clear();\n\n        while ((int)cur.path.size() > k + 1) {\n            int sq = cur.path.back(); cur.path.pop_back();\n            int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n            cur.used.reset1(tid);\n            cur.score -= val[sq];\n            removedSq.push_back(sq);\n            removedTile.push_back(tid);\n        }\n\n        // regrow\n        double a1 = 5.0 + 24.0 * rng.next_double();\n        double a2 = 1.0 + 12.0 * rng.next_double();\n        double g  = 0.05 + 0.65 * rng.next_double();\n        double dp = 20.0 + 55.0 * rng.next_double();\n        extend_greedy(cur, rng, a1, a2, g, dp);\n\n        int delta = cur.score - origScore;\n\n        // SA accept\n        double tr = elapsed / TL;\n        double T0 = 450.0, Tend = 2.0;\n        double T = T0 * pow(Tend / T0, tr);\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            // remove newly added part\n            while ((int)cur.path.size() > k + 1) {\n                int sq = cur.path.back(); cur.path.pop_back();\n                int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n                cur.used.reset1(tid);\n                cur.score -= val[sq];\n            }\n            // restore old suffix\n            for (int i = (int)removedSq.size() - 1; i >= 0; i--) {\n                int sq = removedSq[i];\n                int tid = removedTile[i];\n                cur.path.push_back(sq);\n                cur.tileStack.push_back(tid);\n                cur.used.set1(tid);\n                cur.score += val[sq];\n            }\n        } else {\n            if (cur.score > best.score) best = cur;\n        }\n    }\n\n    // Output directions\n    string out;\n    out.reserve(best.path.size() ? best.path.size() - 1 : 0);\n    for (int i = 1; i < (int)best.path.size(); i++) {\n        int a = best.path[i - 1], b = best.path[i];\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (bi == ai - 1 && bj == aj) out.push_back('U');\n        else if (bi == ai + 1 && bj == aj) out.push_back('D');\n        else if (bi == ai && bj == aj - 1) out.push_back('L');\n        else if (bi == ai && bj == aj + 1) out.push_back('R');\n        else break; // should not happen\n    }\n    cout << out << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horiz; // true: horizontal h[i][j], false: vertical v[i][j]\n    int i, j;\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int HW = 29;\nstatic constexpr int VH = 29;\n\nstruct Solver {\n    double h[N][HW];\n    double v[VH][N];\n    int hc[N][HW];\n    int vc[VH][N];\n\n    vector<EdgeRef> last_edges;\n    double last_pred = 1.0;\n    int k = 0;\n\n    Solver() {\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n            h[i][j] = 5000.0;\n            hc[i][j] = 0;\n        }\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n            v[i][j] = 5000.0;\n            vc[i][j] = 0;\n        }\n    }\n\n    static inline double clampd(double x, double lo, double hi) {\n        return (x < lo) ? lo : (x > hi) ? hi : x;\n    }\n\n    inline double &wref(const EdgeRef &e) { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int &cref(const EdgeRef &e) { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n    inline double wval(const EdgeRef &e) const { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int cval(const EdgeRef &e) const { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n\n    // Identify edge between adjacent nodes u and w, and return its current (non-exploration) weight\n    inline double baseWeight(int u, int w, EdgeRef &eref_out) const {\n        int ui = u / N, uj = u % N;\n        int wi = w / N, wj = w % N;\n        if (ui == wi) {\n            if (wj == uj + 1) eref_out = {true, ui, uj};\n            else              eref_out = {true, ui, wj}; // wj==uj-1\n            double ww = h[eref_out.i][eref_out.j];\n            return clampd(ww, 500.0, 12000.0);\n        } else {\n            if (wi == ui + 1) eref_out = {false, ui, uj};\n            else              eref_out = {false, wi, uj}; // wi==ui-1\n            double ww = v[eref_out.i][eref_out.j];\n            return clampd(ww, 500.0, 12000.0);\n        }\n    }\n\n    inline double planWeight(const EdgeRef &e, int qk) const {\n        double base = clampd(wval(e), 500.0, 12000.0);\n        int cnt = cval(e);\n\n        // exploration fades out in first ~300 queries\n        double phase = (qk < 300) ? (300.0 - qk) / 300.0 : 0.0;\n        double explore = 0.55 * phase;\n\n        // Rarely-used edges slightly cheaper early\n        double w = base / (1.0 + explore / sqrt(cnt + 1.0));\n        return clampd(w, 500.0, 12000.0);\n    }\n\n    vector<int> dijkstraPath(int si, int sj, int ti, int tj, int qk, double explore_override = -1.0) const {\n        int s = si * N + sj, t = ti * N + tj;\n        vector<double> dist(N * N, 1e100);\n        vector<int> prev(N * N, -1);\n        using P = pair<double,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        auto planW = [&](const EdgeRef &e)->double{\n            if (explore_override < 0.0) return planWeight(e, qk);\n            double base = clampd(wval(e), 500.0, 12000.0);\n            int cnt = cval(e);\n            double phase = (qk < 300) ? (300.0 - qk) / 300.0 : 0.0;\n            double explore = explore_override * phase;\n            double w = base / (1.0 + explore / sqrt(cnt + 1.0));\n            return clampd(w, 500.0, 12000.0);\n        };\n\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == t) break;\n\n            int ui = u / N, uj = u % N;\n            auto relax = [&](int w) {\n                EdgeRef e;\n                (void)baseWeight(u, w, e); // fills e\n                double ww = planW(e);\n                double nd = d + ww;\n                if (nd < dist[w]) {\n                    dist[w] = nd;\n                    prev[w] = u;\n                    pq.push({nd, w});\n                }\n            };\n\n            if (uj + 1 < N) relax(u + 1);\n            if (uj - 1 >= 0) relax(u - 1);\n            if (ui + 1 < N) relax(u + N);\n            if (ui - 1 >= 0) relax(u - N);\n        }\n\n        vector<int> nodes;\n        for (int cur = t; cur != -1; cur = prev[cur]) {\n            nodes.push_back(cur);\n            if (cur == s) break;\n        }\n        reverse(nodes.begin(), nodes.end());\n        return nodes;\n    }\n\n    string buildPathAndRecord(const vector<int> &nodes) {\n        last_edges.clear();\n        last_pred = 0.0;\n\n        string path;\n        path.reserve(nodes.size() ? nodes.size() - 1 : 0);\n\n        for (int idx = 0; idx + 1 < (int)nodes.size(); idx++) {\n            int a = nodes[idx], b = nodes[idx + 1];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            if (bi == ai && bj == aj + 1) path.push_back('R');\n            else if (bi == ai && bj == aj - 1) path.push_back('L');\n            else if (bi == ai + 1 && bj == aj) path.push_back('D');\n            else if (bi == ai - 1 && bj == aj) path.push_back('U');\n\n            EdgeRef e;\n            double w = baseWeight(a, b, e);\n            last_edges.push_back(e);\n            last_pred += w;\n        }\n\n        last_pred = max(last_pred, 1.0);\n        return path;\n    }\n\n    string query(int si, int sj, int ti, int tj) {\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        vector<int> nodes = dijkstraPath(si, sj, ti, tj, k);\n        int steps = (int)nodes.size() - 1;\n\n        // guardrails against over-exploration\n        if (steps > manhattan + 60) nodes = dijkstraPath(si, sj, ti, tj, k, 0.20);\n        steps = (int)nodes.size() - 1;\n        if (steps > manhattan + 85) nodes = dijkstraPath(si, sj, ti, tj, k, 0.0);\n\n        return buildPathAndRecord(nodes);\n    }\n\n    void smoothOnce(double s) {\n        // very light smoothing (reduced strength and frequency vs earlier attempts)\n        for (int i = 0; i < N; i++) {\n            double tmp[HW];\n            for (int j = 0; j < HW; j++) {\n                double a = h[i][j];\n                double b = (j > 0 ? h[i][j-1] : h[i][j]);\n                double c = (j + 1 < HW ? h[i][j+1] : h[i][j]);\n                tmp[j] = (a + b + c) / 3.0;\n            }\n            for (int j = 0; j < HW; j++) h[i][j] = (1.0 - s) * h[i][j] + s * tmp[j];\n        }\n        for (int j = 0; j < N; j++) {\n            double tmp[VH];\n            for (int i = 0; i < VH; i++) {\n                double a = v[i][j];\n                double b = (i > 0 ? v[i-1][j] : v[i][j]);\n                double c = (i + 1 < VH ? v[i+1][j] : v[i][j]);\n                tmp[i] = (a + b + c) / 3.0;\n            }\n            for (int i = 0; i < VH; i++) v[i][j] = (1.0 - s) * v[i][j] + s * tmp[i];\n        }\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) h[i][j] = clampd(h[i][j], 500.0, 12000.0);\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) v[i][j] = clampd(v[i][j], 500.0, 12000.0);\n    }\n\n    void feedback(long long observed) {\n        if (last_edges.empty()) { k++; return; }\n\n        double ratio = (double)observed / last_pred;\n        ratio = clampd(ratio, 0.85, 1.18);\n        double logratio = log(ratio);\n\n        // Learning schedule: stable but still adaptive\n        double t = (double)k / 1000.0;\n        double base_lr = 0.85 * (1.0 - t) + 0.25; // 1.10 -> 0.25 (fraction of logratio to apply)\n\n        // Compute normalization denom = sum(share^2 * damp)\n        // share = w / S, damp = 1/sqrt(cnt+1)\n        double denom = 0.0;\n        {\n            for (auto &e : last_edges) {\n                double w = clampd(wval(e), 500.0, 12000.0);\n                double share = w / last_pred;\n                double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n                denom += share * share * damp;\n            }\n        }\n        denom = max(denom, 1e-12);\n        double alpha = base_lr / denom;\n\n        // Apply log-space updates with per-edge damp and contribution share\n        for (auto &e : last_edges) {\n            double w = clampd(wval(e), 500.0, 12000.0);\n            double share = w / last_pred;\n            double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n\n            double dx = alpha * logratio * share * damp;\n\n            // cap per-edge change to stay robust under noise\n            dx = clampd(dx, -0.25, 0.25);\n\n            double &ww = wref(e);\n            ww *= exp(dx);\n            ww = clampd(ww, 500.0, 12000.0);\n\n            cref(e)++;\n        }\n\n        // Light smoothing occasionally after warmup\n        if (k >= 50 && (k % 9 == 8)) smoothOnce(0.02);\n\n        k++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    for (int q = 0; q < 1000; q++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        string path = solver.query(si, sj, ti, tj);\n        cout << path << \"\\n\" << flush;\n\n        long long res;\n        cin >> res;\n        solver.feedback(res);\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr uint8_t DOT = 8; // internal '.' marker (used only in final pruning)\n\n// ---------- RNG (splitmix64) ----------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Hasher {\n    size_t operator()(uint64_t x) const noexcept {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        x ^= (x >> 31);\n        return (size_t)x;\n    }\n};\n\nusing FlatMap = boost::unordered_flat_map<uint64_t, int, Hasher>;\n\n// code = (len<<36) | bits, bits uses 3 bits/char, left-to-right.\nstatic inline uint64_t encodeVec(const vector<uint8_t>& v, int st, int len) {\n    uint64_t bits = 0;\n    for (int i = 0; i < len; i++) bits = (bits << 3) | (uint64_t)v[st + i];\n    return (uint64_t(len) << 36) | bits;\n}\nstatic inline uint64_t encodeFull(const vector<uint8_t>& v) {\n    return encodeVec(v, 0, (int)v.size());\n}\nstatic inline vector<uint8_t> decodeCode(uint64_t code) {\n    int len = int(code >> 36);\n    vector<uint8_t> v(len);\n    uint64_t bits = code & ((len == 0) ? 0ULL : ((1ULL << (3 * len)) - 1ULL));\n    for (int i = len - 1; i >= 0; i--) {\n        v[i] = uint8_t(bits & 7ULL);\n        bits >>= 3;\n    }\n    return v;\n}\n\nstruct CodeBook {\n    int minLen = 2, maxLen = 12;\n    FlatMap code2idx;\n    vector<int> weight;                 // weight per unique code\n    vector<uint64_t> codes;             // code per idx\n    vector<vector<uint8_t>> pattern;    // decoded pattern (optional)\n    long long totalWeight = 0;          // sum weights\n};\n\nstatic CodeBook makeCodeBook(const FlatMap& wmap, int minLen, int maxLen, bool storePattern) {\n    CodeBook book;\n    book.minLen = minLen;\n    book.maxLen = maxLen;\n    book.code2idx.reserve(wmap.size() * 2 + 8);\n    book.weight.reserve(wmap.size());\n    book.codes.reserve(wmap.size());\n\n    int idx = 0;\n    long long sum = 0;\n    for (auto &kv : wmap) {\n        uint64_t code = kv.first;\n        int w = kv.second;\n        book.code2idx.emplace(code, idx++);\n        book.codes.push_back(code);\n        book.weight.push_back(w);\n        sum += w;\n    }\n    book.totalWeight = sum;\n\n    if (storePattern) {\n        book.pattern.resize(book.codes.size());\n        for (int i = 0; i < (int)book.codes.size(); i++) book.pattern[i] = decodeCode(book.codes[i]);\n    }\n    return book;\n}\n\n// ---------- SA state with incremental update ----------\nstruct SAState {\n    array<array<uint8_t, N>, N>* mat = nullptr;\n    const CodeBook* book = nullptr;\n\n    vector<int> occ;              // occ[idx] = total occurrences across all 40 lines\n    long long score = 0;          // sum weight[idx] for occ[idx] > 0\n\n    array<vector<int>, 40> lineIdx;  // for each line, list of matched idx (with multiplicity)\n    vector<int> buf;                // reusable compute buffer\n\n    inline void getLineSeq(int lineId, uint8_t seq[N]) const {\n        if (lineId < 20) {\n            int r = lineId;\n            for (int c = 0; c < N; c++) seq[c] = (*mat)[r][c];\n        } else {\n            int c = lineId - 20;\n            for (int r = 0; r < N; r++) seq[r] = (*mat)[r][c];\n        }\n    }\n\n    inline void computeLineInto(int lineId, vector<int>& out) const {\n        out.clear();\n        uint8_t seq[N];\n        getLineSeq(lineId, seq);\n\n        const int minL = book->minLen;\n        const int maxL = book->maxLen;\n\n        for (int st = 0; st < N; st++) {\n            uint64_t bits = 0;\n            int pos = st;\n            for (int l = 1; l <= maxL; l++) {\n                uint8_t v = seq[pos];\n                if (v == DOT) break;\n                bits = (bits << 3) | (uint64_t)v;\n                if (l >= minL) {\n                    uint64_t code = (uint64_t(l) << 36) | bits;\n                    auto it = book->code2idx.find(code);\n                    if (it != book->code2idx.end()) out.push_back(it->second);\n                }\n                pos++;\n                if (pos == N) pos = 0;\n            }\n        }\n    }\n\n    // swap lineIdx[lineId] with newVec, and update occ/score accordingly.\n    inline void replaceSwapLine(int lineId, vector<int>& newVec) {\n        // remove old\n        for (int idx : lineIdx[lineId]) {\n            int &x = occ[idx];\n            x--;\n            if (x == 0) score -= book->weight[idx];\n        }\n        // add new\n        for (int idx : newVec) {\n            int &x = occ[idx];\n            if (x == 0) score += book->weight[idx];\n            x++;\n        }\n        lineIdx[lineId].swap(newVec); // newVec becomes old content\n    }\n\n    void init(array<array<uint8_t, N>, N>& m, const CodeBook& b) {\n        mat = &m;\n        book = &b;\n        occ.assign(book->codes.size(), 0);\n        score = 0;\n        for (int lineId = 0; lineId < 40; lineId++) {\n            vector<int> tmp;\n            tmp.reserve(256);\n            computeLineInto(lineId, tmp);\n            lineIdx[lineId] = std::move(tmp);\n            for (int idx : lineIdx[lineId]) {\n                int &x = occ[idx];\n                if (x == 0) score += book->weight[idx];\n                x++;\n            }\n        }\n        buf.clear();\n        buf.reserve(256);\n    }\n};\n\nstruct Solver {\n    int M;\n    vector<vector<uint8_t>> inputs;\n    RNG rng;\n    array<array<uint8_t, N>, N> mat;\n    chrono::steady_clock::time_point startTime;\n\n    explicit Solver(int M) : M(M) {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = RNG(seed);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    inline double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    struct CellCh { int r, c; uint8_t oldv; };\n\n    // Apply a set of cell changes (mat already updated), update SAState incrementally, accept by SA rule, else rollback.\n    bool tryApply(SAState& st, const vector<CellCh>& changes, double T) {\n        if (changes.empty()) return false;\n\n        bool mark[40] = {};\n        int lids[40];\n        int lidCount = 0;\n\n        auto addLine = [&](int id) {\n            if (!mark[id]) {\n                mark[id] = true;\n                lids[lidCount++] = id;\n            }\n        };\n\n        for (auto &ch : changes) {\n            addLine(ch.r);\n            addLine(20 + ch.c);\n        }\n\n        long long oldScore = st.score;\n\n        // swap-based backups, no deep copy of existing line vectors\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n\n        vector<int> tmp;\n        tmp.reserve(256);\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp);           // tmp becomes old vector\n            backups.push_back({lid, std::move(tmp)}); // store old vector\n            tmp.clear();\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            // restore line vectors\n            for (int k = (int)backups.size() - 1; k >= 0; k--) {\n                st.replaceSwapLine(backups[k].first, backups[k].second);\n            }\n            // restore cells\n            for (auto &ch : changes) mat[ch.r][ch.c] = ch.oldv;\n        }\n        return accept;\n    }\n\n    void addSubstrings(FlatMap& w, const vector<uint8_t>& s, int minLen, int maxLen, int base) {\n        int L = (int)s.size();\n        for (int len = minLen; len <= maxLen; len++) {\n            if (len > L) break;\n            int mul = base;\n            // mild length bias (longer k-mers are more informative)\n            mul *= (len * len);\n            for (int st = 0; st + len <= L; st++) {\n                w[encodeVec(s, st, len)] += mul;\n            }\n        }\n    }\n\n    // Segment overwrite move: choose input string (or substring) and write into random cyclic row/col segment.\n    bool doSegmentOverwrite(SAState& st, double T, int minK, int maxK) {\n        int idx = rng.nextInt(0, M - 1);\n        const auto& s = inputs[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n\n        int k;\n        if (rng.nextDouble() < 0.55) {\n            k = min(L, maxK);\n        } else {\n            k = rng.nextInt(minK, min(maxK, L));\n        }\n        int off = rng.nextInt(0, L - k);\n\n        bool vert = (rng.nextInt(0, 1) == 1);\n        int line = rng.nextInt(0, N - 1);\n        int start = rng.nextInt(0, N - 1);\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n\n        if (!vert) {\n            int r = line;\n            for (int t = 0; t < k; t++) {\n                int c = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = line;\n            for (int t = 0; t < k; t++) {\n                int r = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApply(st, changes, T);\n    }\n\n    // Single-cell mutation\n    bool doCellMutate(SAState& st, double T) {\n        int i = rng.nextInt(0, N - 1);\n        int j = rng.nextInt(0, N - 1);\n        uint8_t oldv = mat[i][j];\n        uint8_t nv = oldv;\n        while (nv == oldv) nv = (uint8_t)rng.nextInt(0, 7);\n        mat[i][j] = nv;\n        vector<CellCh> changes = { {i, j, oldv} };\n        return tryApply(st, changes, T);\n    }\n\n    // Impose uncovered full string: pick uncovered code, try a few placements, apply with SA acceptance.\n    bool doImposeUncovered(SAState& st, double T, int trials = 50) {\n        if (st.book->pattern.empty()) return false;\n        if (st.score >= st.book->totalWeight) return false;\n\n        int U = (int)st.occ.size();\n        int target = -1;\n        for (int t = 0; t < 40; t++) {\n            int cand = rng.nextInt(0, U - 1);\n            if (st.occ[cand] == 0) { target = cand; break; }\n        }\n        if (target < 0) return false;\n\n        const auto& pat = st.book->pattern[target];\n        int k = (int)pat.size();\n        if (k < 2) return false;\n\n        bool bestVert = false;\n        int bestLine = 0, bestStart = 0;\n        int bestMismatch = 1e9;\n\n        for (int t = 0; t < trials; t++) {\n            bool vert = (rng.nextInt(0, 1) == 1);\n            int line = rng.nextInt(0, N - 1);\n            int start = rng.nextInt(0, N - 1);\n            int mism = 0;\n            if (!vert) {\n                int r = line;\n                for (int x = 0; x < k; x++) mism += (mat[r][(start + x) % N] != pat[x]);\n            } else {\n                int c = line;\n                for (int x = 0; x < k; x++) mism += (mat[(start + x) % N][c] != pat[x]);\n            }\n            if (mism < bestMismatch) {\n                bestMismatch = mism;\n                bestVert = vert;\n                bestLine = line;\n                bestStart = start;\n                if (bestMismatch == 0) break;\n            }\n        }\n        if (bestMismatch == 0) return false; // already occurs somehow\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n        if (!bestVert) {\n            int r = bestLine;\n            for (int x = 0; x < k; x++) {\n                int c = (bestStart + x) % N;\n                uint8_t nv = pat[x];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = bestLine;\n            for (int x = 0; x < k; x++) {\n                int r = (bestStart + x) % N;\n                uint8_t nv = pat[x];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApply(st, changes, T);\n    }\n\n    void anneal(SAState& st, double tStart, double tEnd,\n                double T0, double T1,\n                double pSeg, double pImpose, int segMinK, int segMaxK, bool allowImpose) {\n        while (true) {\n            double now = elapsedSec();\n            if (now >= tEnd) break;\n            double prog = (now - tStart) / max(1e-9, (tEnd - tStart));\n            prog = min(1.0, max(0.0, prog));\n            double T = T0 * pow(T1 / T0, prog);\n\n            double r = rng.nextDouble();\n            if (allowImpose && r < pImpose) {\n                doImposeUncovered(st, T);\n            } else if (r < pImpose + pSeg) {\n                doSegmentOverwrite(st, T, segMinK, segMaxK);\n            } else {\n                doCellMutate(st, T);\n            }\n        }\n    }\n\n    // Final greedy improvement: accept only if full coverage count increases.\n    void greedyFinishFull(SAState& st, double tEnd) {\n        if (st.book->pattern.empty()) return;\n        while (elapsedSec() < tEnd) {\n            long long before = st.score;\n            // Use low \"temperature\": only accept improvements.\n            // Implement by calling impose and then checking.\n            // We use a dummy very small T and also reject if not improved.\n            // (tryApply inside doImpose can accept negative with SA; avoid that by just re-checking.)\n            array<array<uint8_t, N>, N> backupMat = mat;\n            vector<int> backupOcc = st.occ;\n            long long backupScore = st.score;\n            auto backupLines = st.lineIdx;\n\n            doImposeUncovered(st, /*T*/1e-9, 80);\n            if (st.score <= before) {\n                // rollback\n                mat = backupMat;\n                st.occ = std::move(backupOcc);\n                st.score = backupScore;\n                st.lineIdx = std::move(backupLines);\n                // If we couldn't improve, stop early with some probability to save time\n                if (rng.nextDouble() < 0.25) break;\n            }\n        }\n    }\n\n    void pruneDotsIfAllCovered(const CodeBook& fullBook) {\n        SAState st;\n        st.init(mat, fullBook);\n        if (st.score != fullBook.totalWeight) return;\n\n        vector<int> order(N * N);\n        iota(order.begin(), order.end(), 0);\n        for (int k = (int)order.size() - 1; k > 0; k--) {\n            int r = rng.nextInt(0, k);\n            swap(order[k], order[r]);\n        }\n\n        for (int p : order) {\n            int i = p / N, j = p % N;\n            if (mat[i][j] == DOT) continue;\n            uint8_t oldv = mat[i][j];\n            mat[i][j] = DOT;\n\n            vector<CellCh> changes = { {i, j, oldv} };\n            // accept only if still all covered\n            long long oldScore = st.score;\n            bool ok = tryApply(st, changes, /*T*/1e-12);\n            if (!ok) continue; // reverted by SA rule (shouldn't happen due to T tiny)\n            if (st.score != fullBook.totalWeight) {\n                // force rollback (tryApply accepted; revert manually)\n                // easiest: revert cell and recompute affected lines properly by undoing with another tryApply\n                mat[i][j] = oldv;\n                vector<CellCh> back = { {i, j, DOT} };\n                tryApply(st, back, /*T*/1e9); // accept surely (delta>=0 usually), just to sync\n                // If the accept happened to reject (unlikely), re-init\n                if (mat[i][j] != oldv) {\n                    mat[i][j] = oldv;\n                    st.init(mat, fullBook);\n                }\n            }\n        }\n    }\n\n    void solveAndPrint() {\n        // Slightly better init: sample letters according to global frequency in reads.\n        array<long long, 8> freq{};\n        long long tot = 0;\n        for (auto &s : inputs) for (uint8_t v : s) { freq[v]++; tot++; }\n        if (tot > 0) {\n            vector<double> acc(8);\n            double sum = 0;\n            for (int i = 0; i < 8; i++) sum += (double)freq[i] + 1.0;\n            double cur = 0;\n            for (int i = 0; i < 8; i++) {\n                cur += ((double)freq[i] + 1.0) / sum;\n                acc[i] = cur;\n            }\n            for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n                double r = rng.nextDouble();\n                int v = 0;\n                while (v < 7 && r > acc[v]) v++;\n                mat[i][j] = (uint8_t)v;\n            }\n        }\n\n        // Build phase books:\n        // A: k-mers 3..7 only\n        // B: k-mers 4..8 + full strings with boosted weight\n        // C: full strings only (true objective)\n        FlatMap wA; wA.reserve((size_t)20000);\n        FlatMap wB; wB.reserve((size_t)30000);\n        FlatMap wC; wC.reserve((size_t)2048);\n\n        const int FULL_BOOST = 80; // weight multiplier in phase B\n\n        for (auto &s : inputs) {\n            // full strings for B and C\n            wB[encodeFull(s)] += FULL_BOOST;\n            wC[encodeFull(s)] += 1;\n\n            addSubstrings(wA, s, 3, 7, 1);\n            addSubstrings(wB, s, 4, 8, 1);\n        }\n\n        CodeBook bookA = makeCodeBook(wA, 3, 7, false);\n        CodeBook bookB = makeCodeBook(wB, 2, 12, false);\n        CodeBook bookC = makeCodeBook(wC, 2, 12, true);\n\n        startTime = chrono::steady_clock::now();\n        double TL = 2.90;\n\n        SAState st;\n\n        // Phase A\n        st.init(mat, bookA);\n        anneal(st, 0.0, 0.95, 4000.0, 40.0,\n               /*pSeg*/0.10, /*pImpose*/0.0, /*segMinK*/4, /*segMaxK*/8, /*allowImpose*/false);\n\n        // Phase B\n        st.init(mat, bookB);\n        anneal(st, 0.95, 2.40, 2500.0, 15.0,\n               /*pSeg*/0.14, /*pImpose*/0.0, /*segMinK*/5, /*segMaxK*/12, /*allowImpose*/false);\n\n        // Phase C (true objective)\n        st.init(mat, bookC);\n        array<array<uint8_t, N>, N> bestMat = mat;\n        long long bestScore = st.score;\n\n        // a bit of SA with stronger impose/segment\n        while (elapsedSec() < TL - 0.20) {\n            double now = elapsedSec();\n            double rem = (TL - 0.20) - now;\n            if (rem <= 0) break;\n            double tStart = now;\n            double tEnd = now + min(0.20, rem);\n\n            anneal(st, tStart, tEnd, 80.0, 0.8,\n                   /*pSeg*/0.10, /*pImpose*/0.14, /*segMinK*/6, /*segMaxK*/12, /*allowImpose*/true);\n\n            if (st.score > bestScore) {\n                bestScore = st.score;\n                bestMat = mat;\n            }\n        }\n        mat = bestMat;\n        st.init(mat, bookC);\n\n        // Greedy finishing\n        greedyFinishFull(st, TL - 0.05);\n\n        // If perfect, try to introduce '.' safely\n        pruneDotsIfAllCovered(bookC);\n\n        // Output\n        for (int i = 0; i < N; i++) {\n            string out;\n            out.reserve(N);\n            for (int j = 0; j < N; j++) {\n                uint8_t v = mat[i][j];\n                if (v == DOT) out.push_back('.');\n                else out.push_back(char('A' + v));\n            }\n            cout << out << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, M;\n    cin >> n >> M;\n\n    Solver solver(M);\n    solver.inputs.reserve(M);\n\n    for (int i = 0; i < M; i++) {\n        string s;\n        cin >> s;\n        vector<uint8_t> v;\n        v.reserve(s.size());\n        for (char c : s) v.push_back((uint8_t)(c - 'A')); // 'A'..'H' -> 0..7\n        solver.inputs.push_back(std::move(v));\n    }\n\n    solver.solveAndPrint();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed=88172645463325252ULL) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    uint64_t operator()() { return next(); }\n    int next_int(int lo, int hi) { return lo + (int)(next() % (uint64_t)(hi - lo + 1)); }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj;\n    vector<int> dist;\n    vector<int> pairU, pairV;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    void add_edge(int u, int v) { adj[u].push_back(v); }\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                int u2 = pairV[v];\n                if(u2 != -1 && dist[u2] == -1){\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n                if(u2 == -1) found = true;\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for(int v: adj[u]){\n            int u2 = pairV[v];\n            if(u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))){\n                pairU[u] = v;\n                pairV[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        pairU.assign(nL, -1);\n        pairV.assign(nR, -1);\n        int matching = 0;\n        while(bfs()){\n            for(int u=0; u<nL; u++){\n                if(pairU[u] == -1 && dfs(u)) matching++;\n            }\n        }\n        return matching;\n    }\n\n    // After max_matching(), returns min vertex cover as (coverL, coverR)\n    // Standard: BFS from unmatched L using alternating paths (non-matching L->R, matching R->L).\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                if(pairU[u] == v) continue; // only non-matching edges L->R\n                if(!visR[v]){\n                    visR[v] = 1;\n                    int u2 = pairV[v]; // matching edge R->L\n                    if(u2 != -1 && !visL[u2]){\n                        visL[u2] = 1;\n                        q.push(u2);\n                    }\n                }\n            }\n        }\n        // min vertex cover: (L \\ Z) \u222a (R \u2229 Z)\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for(int u=0; u<nL; u++) if(!visL[u]) coverL[u] = 1;\n        for(int v=0; v<nR; v++) if(visR[v])  coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct Solver {\n    int N, si, sj;\n    vector<string> c;\n\n    vector<vector<int>> id; // -1 for obstacle\n    vector<int> xs, ys, w;  // per node\n    int R = 0;\n\n    vector<int> hseg, vseg;\n    int H = 0, V = 0;\n\n    // Visibility bitsets (for final relaxation / safety)\n    int W64 = 0;\n    vector<uint64_t> hbits, vbits;\n    vector<uint64_t> visFlat;\n    vector<uint64_t> allMask;\n\n    // Dijkstra buffers\n    static constexpr long long INF = (1LL<<60);\n    vector<long long> dist;\n    vector<int> prevv;\n\n    inline bool inb(int x,int y) const { return 0<=x && x<N && 0<=y && y<N; }\n\n    void read() {\n        cin >> N >> si >> sj;\n        c.resize(N);\n        for(int i=0;i<N;i++) cin >> c[i];\n    }\n\n    void build_nodes() {\n        id.assign(N, vector<int>(N, -1));\n        xs.clear(); ys.clear(); w.clear();\n        R = 0;\n        for(int i=0;i<N;i++){\n            for(int j=0;j<N;j++){\n                if(c[i][j] == '#') continue;\n                id[i][j] = R++;\n                xs.push_back(i);\n                ys.push_back(j);\n                w.push_back(c[i][j]-'0');\n            }\n        }\n        dist.assign(R, INF);\n        prevv.assign(R, -1);\n        hseg.assign(R, -1);\n        vseg.assign(R, -1);\n    }\n\n    void build_segments() {\n        H = 0;\n        for(int i=0;i<N;i++){\n            int j=0;\n            while(j<N){\n                if(id[i][j] == -1){ j++; continue; }\n                int sid = H++;\n                while(j<N && id[i][j] != -1){\n                    hseg[id[i][j]] = sid;\n                    j++;\n                }\n            }\n        }\n        V = 0;\n        for(int j=0;j<N;j++){\n            int i=0;\n            while(i<N){\n                if(id[i][j] == -1){ i++; continue; }\n                int sid = V++;\n                while(i<N && id[i][j] != -1){\n                    vseg[id[i][j]] = sid;\n                    i++;\n                }\n            }\n        }\n    }\n\n    void build_visibility_bitsets() {\n        W64 = (R + 63) / 64;\n        hbits.assign((size_t)H * W64, 0ULL);\n        vbits.assign((size_t)V * W64, 0ULL);\n        visFlat.assign((size_t)R * W64, 0ULL);\n\n        for(int v=0; v<R; v++){\n            int hi=hseg[v], vi=vseg[v];\n            int word=v>>6, bit=v&63;\n            hbits[(size_t)hi * W64 + word] |= (1ULL<<bit);\n            vbits[(size_t)vi * W64 + word] |= (1ULL<<bit);\n        }\n        for(int v=0; v<R; v++){\n            uint64_t* dst = &visFlat[(size_t)v * W64];\n            const uint64_t* hb = &hbits[(size_t)hseg[v] * W64];\n            const uint64_t* vb = &vbits[(size_t)vseg[v] * W64];\n            for(int k=0;k<W64;k++) dst[k] = hb[k] | vb[k];\n        }\n\n        allMask.assign(W64, ~0ULL);\n        if(R % 64 != 0) allMask[W64-1] = (1ULL << (R%64)) - 1ULL;\n    }\n\n    inline void for_neighbors(int v, const function<void(int)>& f) const {\n        int x=xs[v], y=ys[v];\n        if(x>0){ int u=id[x-1][y]; if(u!=-1) f(u); }\n        if(x+1<N){ int u=id[x+1][y]; if(u!=-1) f(u); }\n        if(y>0){ int u=id[x][y-1]; if(u!=-1) f(u); }\n        if(y+1<N){ int u=id[x][y+1]; if(u!=-1) f(u); }\n    }\n\n    template<class Pred>\n    int dijkstra_until(int s, Pred pred) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            if(pred(v)) return v;\n            for_neighbors(v, [&](int to){\n                long long nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push({nd,to});\n                }\n            });\n        }\n        return -1;\n    }\n\n    void dijkstra_all(int s) {\n        fill(dist.begin(), dist.end(), INF);\n        using P = pair<long long,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            for_neighbors(v, [&](int to){\n                long long nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    pq.push({nd,to});\n                }\n            });\n        }\n    }\n\n    vector<int> restore_path(int s, int t) {\n        vector<int> path;\n        int cur = t;\n        while(cur != -1){\n            path.push_back(cur);\n            if(cur == s) break;\n            cur = prevv[cur];\n        }\n        reverse(path.begin(), path.end());\n        if(path.empty() || path.front() != s) return {s}; // safety fallback\n        return path;\n    }\n\n    long long route_time(const vector<int>& route) const {\n        long long t=0;\n        for(size_t i=1;i<route.size();i++) t += w[route[i]];\n        return t;\n    }\n\n    struct Required {\n        vector<char> needH, needV;\n        int total = 0;\n    };\n\n    Required compute_required_by_min_vertex_cover() {\n        // Build bipartite graph edges (H -> V) using all cells (edges).\n        vector<vector<int>> adj(H);\n        for(int v=0; v<R; v++){\n            adj[hseg[v]].push_back(vseg[v]);\n        }\n        for(int u=0; u<H; u++){\n            auto &vec = adj[u];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n        }\n\n        HopcroftKarp hk(H, V);\n        hk.adj = std::move(adj);\n        hk.max_matching();\n        auto [coverL, coverR] = hk.min_vertex_cover();\n\n        Required req;\n        req.needH = std::move(coverL);\n        req.needV = std::move(coverR);\n        req.total = 0;\n        for(char x: req.needH) req.total += (x!=0);\n        for(char x: req.needV) req.total += (x!=0);\n\n        // Safety: if something goes wrong (shouldn't), fall back to all horizontals.\n        if(req.total == 0){\n            req.needH.assign(H, 1);\n            req.needV.assign(V, 0);\n            req.total = H;\n        }\n        return req;\n    }\n\n    // Build a greedy route that covers all required segments; also outputs the \"stop nodes\" (waypoints)\n    vector<int> build_greedy_route_required(int startId, const Required& req, vector<int>& stops) {\n        vector<char> coveredH(H, 0), coveredV(V, 0);\n        int rem = req.total;\n\n        auto cover_node = [&](int v){\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi] && !coveredH[hi]){ coveredH[hi]=1; rem--; }\n            if(req.needV[vi] && !coveredV[vi]){ coveredV[vi]=1; rem--; }\n        };\n\n        vector<int> route;\n        route.push_back(startId);\n        cover_node(startId);\n\n        stops.clear();\n        stops.push_back(startId);\n\n        int cur = startId;\n        while(rem > 0){\n            int target = dijkstra_until(cur, [&](int v){\n                int hi=hseg[v], vi=vseg[v];\n                return (req.needH[hi] && !coveredH[hi]) || (req.needV[vi] && !coveredV[vi]);\n            });\n            if(target == -1) break; // should not happen\n\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++){\n                route.push_back(path[i]);\n                cover_node(path[i]);\n            }\n            cur = target;\n            stops.push_back(cur);\n        }\n\n        // return to start\n        if(cur != startId){\n            int target = dijkstra_until(cur, [&](int v){ return v == startId; });\n            auto path = restore_path(cur, target);\n            for(size_t i=1;i<path.size();i++) route.push_back(path[i]);\n        }\n\n        // avoid t=0\n        if(route.size() == 1 && R > 1){\n            int nb = -1;\n            for_neighbors(startId, [&](int to){ if(nb==-1) nb=to; });\n            if(nb != -1){\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n        }\n        return route;\n    }\n\n    // Remove redundant stops while preserving required coverage (stop covers at most two required segments).\n    void prune_redundant_stops(vector<int>& stops, const Required& req) {\n        if(stops.size() <= 1) return;\n        // Remove consecutive duplicates\n        {\n            vector<int> tmp;\n            tmp.reserve(stops.size());\n            for(int v: stops){\n                if(tmp.empty() || tmp.back() != v) tmp.push_back(v);\n            }\n            stops.swap(tmp);\n        }\n\n        vector<int> cntH(H, 0), cntV(V, 0);\n        auto add = [&](int v, int delta){\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi]) cntH[hi] += delta;\n            if(req.needV[vi]) cntV[vi] += delta;\n        };\n        for(int v: stops) add(v, +1);\n\n        vector<char> keep(stops.size(), 1);\n        keep[0] = 1; // keep start\n\n        // Try removing in reverse (often helps)\n        for(int i=(int)stops.size()-1; i>=1; i--){\n            int v = stops[i];\n            int hi=hseg[v], vi=vseg[v];\n            bool ok = true;\n            if(req.needH[hi] && cntH[hi] <= 1) ok = false;\n            if(req.needV[vi] && cntV[vi] <= 1) ok = false;\n            if(ok){\n                keep[i] = 0;\n                add(v, -1);\n            }\n        }\n        vector<int> out;\n        out.reserve(stops.size());\n        for(size_t i=0;i<stops.size();i++) if(keep[i]) out.push_back(stops[i]);\n        stops.swap(out);\n    }\n\n    // Build all-pairs shortest path distances between waypoints (directed).\n    vector<vector<int>> build_waypoint_dist(const vector<int>& wp) {\n        int m = (int)wp.size();\n        vector<vector<int>> D(m, vector<int>(m, INT_MAX/4));\n        for(int i=0;i<m;i++){\n            dijkstra_all(wp[i]);\n            for(int j=0;j<m;j++){\n                long long d = dist[wp[j]];\n                if(d >= INF/2) D[i][j] = INT_MAX/4;\n                else D[i][j] = (int)d;\n            }\n        }\n        return D;\n    }\n\n    long long cycle_cost(const vector<int>& seq, const vector<vector<int>>& D) {\n        int m = (int)seq.size();\n        long long cost = 0;\n        for(int i=0;i<m;i++){\n            int a = seq[i];\n            int b = seq[(i+1)%m];\n            cost += D[a][b];\n        }\n        return cost;\n    }\n\n    // Hillclimb on a directed cycle with fixed start at pos 0.\n    // seq contains indices into wp (not node ids). seq[0] must be 0.\n    void optimize_waypoint_order(vector<int>& seq, const vector<vector<int>>& D, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        int m = (int)seq.size();\n        if(m <= 3) return;\n\n        auto prev_idx = [&](int i){ return (i-1+m)%m; };\n        auto next_idx = [&](int i){ return (i+1)%m; };\n\n        long long best = cycle_cost(seq, D);\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            uint64_t r = rng();\n            if((r & 1ULL) == 0ULL){\n                // Relocate (insertion)\n                int i = 1 + (int)(rng() % (uint64_t)(m-1)); // move this\n                int j = (int)(rng() % (uint64_t)m);        // insert after this\n                if(j == i) continue;\n                if(next_idx(j) == i) continue; // no-op\n\n                int pi = prev_idx(i), ni = next_idx(i);\n                int a = seq[pi], x = seq[i], b = seq[ni];\n                int c = seq[j], d = seq[next_idx(j)];\n\n                long long old = (long long)D[a][x] + D[x][b] + D[c][d];\n                long long neu = (long long)D[a][b] + D[c][x] + D[x][d];\n                long long delta = neu - old;\n                if(delta >= 0) continue;\n\n                // apply relocate in seq (on linear vector, careful with indices)\n                int xval = seq[i];\n                if(i < j){\n                    seq.erase(seq.begin() + i);\n                    seq.insert(seq.begin() + j, xval); // after erase, j shifts left by 1, inserting at j places x before old seq[j+1], which is after old j\n                }else{\n                    seq.erase(seq.begin() + i);\n                    seq.insert(seq.begin() + j + 1, xval);\n                }\n                // ensure start fixed\n                if(seq[0] != 0){\n                    // rotate back so that 0 at front (shouldn't happen because we never move 0)\n                    auto it = find(seq.begin(), seq.end(), 0);\n                    rotate(seq.begin(), it, seq.end());\n                }\n                best += delta;\n            }else{\n                // Swap\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = 1 + (int)(rng() % (uint64_t)(m-1));\n                if(i == j) continue;\n                if(i > j) swap(i,j);\n\n                int pi = prev_idx(i), ni = next_idx(i);\n                int pj = prev_idx(j), nj = next_idx(j);\n\n                int a = seq[pi], b = seq[i], c = seq[ni];\n                int d = seq[pj], e = seq[j], f = seq[nj];\n\n                long long old, neu;\n                if(ni == j){ // adjacent i -> j\n                    old = (long long)D[a][b] + D[b][e] + D[e][f];\n                    neu = (long long)D[a][e] + D[e][b] + D[b][f];\n                }else{\n                    old = (long long)D[a][b] + D[b][c] + D[d][e] + D[e][f];\n                    neu = (long long)D[a][e] + D[e][c] + D[d][b] + D[b][f];\n                }\n                long long delta = neu - old;\n                if(delta >= 0) continue;\n\n                swap(seq[i], seq[j]);\n                best += delta;\n            }\n        }\n    }\n\n    vector<int> build_route_from_waypoints(const vector<int>& wpNodesInOrder) {\n        int m = (int)wpNodesInOrder.size();\n        vector<int> route;\n        route.push_back(wpNodesInOrder[0]);\n\n        for(int i=0;i<m;i++){\n            int s = wpNodesInOrder[i];\n            int t = wpNodesInOrder[(i+1)%m];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            (void)reached;\n            auto path = restore_path(s, t);\n            for(size_t k=1;k<path.size();k++) route.push_back(path[k]);\n        }\n\n        // avoid t=0\n        if(route.size() == 1 && R > 1){\n            int startId = route[0];\n            int nb=-1;\n            for_neighbors(startId, [&](int to){ if(nb==-1) nb=to; });\n            if(nb!=-1){\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n        }\n        return route;\n    }\n\n    pair<bool,long long> eval_required(const vector<int>& route, const Required& req) const {\n        vector<char> seenH(H, 0), seenV(V, 0);\n        int rem = req.total;\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            int hi=hseg[v], vi=vseg[v];\n            if(req.needH[hi] && !seenH[hi]){ seenH[hi]=1; rem--; }\n            if(req.needV[vi] && !seenV[vi]){ seenV[vi]=1; rem--; }\n        }\n        return {rem==0, t};\n    }\n\n    pair<bool,long long> eval_full_visibility(const vector<int>& route) const {\n        vector<uint64_t> cov(W64, 0ULL);\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            const uint64_t* vb = &visFlat[(size_t)v * W64];\n            for(int k=0;k<W64;k++) cov[k] |= vb[k];\n        }\n        for(int k=0;k<W64;k++){\n            if(cov[k] != allMask[k]) return {false, t};\n        }\n        return {true, t};\n    }\n\n    vector<int> improve_by_shortcuts_required(vector<int> route, const Required& req, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_required(route, req);\n        (void)ok0;\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 10) continue;\n\n            int len = 5 + (int)(rng() % 220);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin() + a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_required(nr, req);\n            if(ok && newT < bestT){\n                route.swap(nr);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    vector<int> improve_by_shortcuts_full(vector<int> route, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_full_visibility(route);\n        if(!ok0) return route;\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L = (int)route.size();\n            if(L < 10) continue;\n\n            int len = 5 + (int)(rng() % 180);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            long long oldCost = 0;\n            for(int i=a+1;i<=b;i++) oldCost += w[route[i]];\n\n            int s = route[a], t = route[b];\n            int reached = dijkstra_until(s, [&](int v){ return v == t; });\n            if(reached != t) continue;\n            long long newCost = dist[t];\n            if(newCost >= oldCost) continue;\n\n            auto path = restore_path(s, t);\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin() + a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin() + b + 1, route.end());\n\n            auto [ok, newT] = eval_full_visibility(nr);\n            if(ok && newT < bestT){\n                route.swap(nr);\n                bestT = newT;\n            }\n        }\n        return route;\n    }\n\n    string route_to_moves(const vector<int>& route) const {\n        string out;\n        out.reserve(route.size() ? route.size()-1 : 0);\n        for(size_t i=1;i<route.size();i++){\n            int a=route[i-1], b=route[i];\n            int x1=xs[a], y1=ys[a], x2=xs[b], y2=ys[b];\n            if(x2==x1-1 && y2==y1) out.push_back('U');\n            else if(x2==x1+1 && y2==y1) out.push_back('D');\n            else if(x2==x1 && y2==y1-1) out.push_back('L');\n            else if(x2==x1 && y2==y1+1) out.push_back('R');\n            else {\n                // Should never happen\n            }\n        }\n        return out;\n    }\n\n    void solve() {\n        read();\n        build_nodes();\n        build_segments();\n        build_visibility_bitsets();\n\n        int startId = id[si][sj];\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        auto globalSt = chrono::steady_clock::now();\n\n        // 1) Compute required segments via minimum vertex cover\n        Required req = compute_required_by_min_vertex_cover();\n\n        // 2) Greedy covering route + stops\n        vector<int> stops;\n        vector<int> route0 = build_greedy_route_required(startId, req, stops);\n\n        // 3) Prune redundant stops\n        prune_redundant_stops(stops, req);\n\n        // 4) Directed TSP-like improvement on stops using all-pairs distances\n        // Build waypoint list (node ids) and index-cycle (indices into wp)\n        vector<int> wp = stops; // node ids, wp[0] is start\n        int m = (int)wp.size();\n        if(m >= 2){\n            // Build distance matrix between waypoint indices\n            auto D = build_waypoint_dist(wp);\n\n            vector<int> seq(m);\n            iota(seq.begin(), seq.end(), 0); // start with current order\n            // optimize time budget based on remaining\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n            double budget = max(0.2, 1.0 - elapsed);\n            optimize_waypoint_order(seq, D, budget, rng);\n\n            // Convert optimized seq of indices into node ids in that order\n            vector<int> wpOrder;\n            wpOrder.reserve(m);\n            for(int idx: seq) wpOrder.push_back(wp[idx]);\n\n            // Rebuild route from optimized waypoints\n            route0 = build_route_from_waypoints(wpOrder);\n        }\n\n        // 5) Shortcut improvement while preserving required segments\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n        double remain = 2.85 - elapsed;\n        if(remain > 0.10){\n            double t1 = min(0.9, remain * 0.55);\n            route0 = improve_by_shortcuts_required(std::move(route0), req, t1, rng);\n        }\n\n        // 6) Final relaxation: allow changing the implicit cover, only enforce full visibility\n        elapsed = chrono::duration<double>(chrono::steady_clock::now() - globalSt).count();\n        remain = 2.90 - elapsed;\n        if(remain > 0.08){\n            route0 = improve_by_shortcuts_full(std::move(route0), remain, rng);\n        }\n\n        cout << route_to_moves(route0) << \"\\n\";\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver s;\n    s.solve();\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct MaxPairCmp {\n    bool operator()(const pair<long long,int>& a, const pair<long long,int>& b) const {\n        return a.first < b.first; // max-heap\n    }\n};\n\nstatic inline double clampd(double x, double lo, double hi){\n    if(x < lo) return lo;\n    if(x > hi) return hi;\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N,M,K,R;\n    cin >> N >> M >> K >> R;\n\n    vector<vector<int>> d(N, vector<int>(K));\n    for(int i=0;i<N;i++){\n        for(int k=0;k<K;k++) cin >> d[i][k];\n    }\n\n    vector<vector<int>> g(N);\n    vector<int> indeg(N,0), outdeg(N,0);\n    for(int i=0;i<R;i++){\n        int u,v; cin >> u >> v;\n        --u; --v;\n        g[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    // critical path length (works by index because u < v)\n    vector<int> cp(N,1);\n    for(int i=N-1;i>=0;i--){\n        int best=1;\n        for(int v: g[i]) best = max(best, 1 + cp[v]);\n        cp[i]=best;\n    }\n\n    vector<int> diff(N,0);\n    for(int i=0;i<N;i++){\n        int s=0;\n        for(int k=0;k<K;k++) s += d[i][k];\n        diff[i]=s;\n    }\n\n    // base static key for extracting high-priority tasks\n    vector<long long> baseKey(N);\n    for(int i=0;i<N;i++){\n        baseKey[i] = (long long)cp[i]*1'000'000LL\n                   + (long long)diff[i]*1'000LL\n                   + (long long)outdeg[i]*10LL\n                   - (long long)i;\n    }\n\n    // state: 0 not started, 1 in progress, 2 done\n    vector<int> state(N,0);\n\n    // Ready management\n    vector<char> in_ready(N, 0);\n    vector<int> ready_since(N, 0);\n\n    // Two PQs: by priority and by age (oldest first)\n    priority_queue<pair<long long,int>, vector<pair<long long,int>>, MaxPairCmp> pq_key;\n    priority_queue<pair<long long,int>, vector<pair<long long,int>>, MaxPairCmp> pq_age;\n\n    auto push_ready = [&](int task, int day){\n        if(in_ready[task]) return;\n        if(state[task] != 0) return;\n        if(indeg[task] != 0) return;\n        in_ready[task] = 1;\n        // day when it became ready (end of that day). initial tasks use 0.\n        // use negative for age ordering: older (smaller ready_since) -> larger key\n        pq_key.push({baseKey[task], task});\n        pq_age.push({-(long long)ready_since[task], task});\n    };\n\n    // initialize ready tasks\n    for(int i=0;i<N;i++){\n        if(indeg[i]==0){\n            ready_since[i]=0;\n            push_ready(i, 0);\n        }\n    }\n\n    // Member/task status\n    vector<int> member_task(M, -1);\n    vector<int> member_start(M, -1);\n\n    // Skill estimates\n    const double SKILL_INIT = 10.0;\n    const double SKILL_MIN = 0.0;\n    const double SKILL_MAX = 80.0;\n    vector<vector<double>> shat(M, vector<double>(K, SKILL_INIT));\n    vector<int> samples(M, 0);\n\n    auto predict_w = [&](int task, int mem)->double{\n        double w=0.0;\n        for(int k=0;k<K;k++){\n            double def = (double)d[task][k] - shat[mem][k];\n            if(def > 0) w += def;\n        }\n        return w;\n    };\n\n    auto predict_time = [&](int task, int mem)->double{\n        // Conservative bias + uncertainty for low samples\n        double w = predict_w(task, mem);\n        double uncert = 1.5 / sqrt(1.0 + samples[mem]);\n        double bias = 0.6; // mild safety buffer\n        return max(1.0, w + bias + uncert);\n    };\n\n    auto update_skill_interval = [&](int mem, int task, int t_obs){\n        // Convert observed duration to an interval for w, considering r_i in [-3,3].\n        // Also note that when w>0, t can still be 1, so t==1 only gives w<=4.\n        double lo, hi;\n        if(t_obs <= 1){\n            lo = 0.0;\n            hi = 4.0;\n        }else{\n            lo = max(1.0, (double)t_obs - 3.0);\n            hi = (double)t_obs + 3.0;\n        }\n\n        vector<double> def(K);\n        vector<int> active;\n        active.reserve(K);\n        double w_hat=0.0;\n\n        for(int k=0;k<K;k++){\n            def[k] = max(0.0, (double)d[task][k] - shat[mem][k]);\n            if(def[k] > 1e-12) active.push_back(k);\n            w_hat += def[k];\n        }\n\n        if(lo - 1e-9 <= w_hat && w_hat <= hi + 1e-9) return;\n\n        double lr = 0.8 / sqrt(1.0 + samples[mem]); // decreasing step size\n\n        if(w_hat > hi){\n            // Need to reduce w -> increase skills on active dimensions.\n            double delta_total = w_hat - hi;\n            double step = lr * delta_total;\n\n            if(active.empty()) return; // w_hat=0 can't be >hi\n            // distribute proportionally to current deficits\n            for(int k: active){\n                double frac = def[k] / w_hat;\n                double inc = step * frac;\n                // can't remove more deficit than exists (cap at def[k])\n                inc = min(inc, def[k]);\n                shat[mem][k] = clampd(shat[mem][k] + inc, SKILL_MIN, SKILL_MAX);\n            }\n        }else{ // w_hat < lo\n            // Need to increase w -> decrease skills.\n            double delta_total = lo - w_hat;\n            double step = lr * delta_total;\n\n            if(!active.empty()){\n                // easiest: decrease already-active dims (increases w 1-to-1)\n                double wsum = 0.0;\n                for(int k: active) wsum += (def[k] + 1.0); // avoid too peaky when def small\n                for(int k: active){\n                    double frac = (def[k] + 1.0) / wsum;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }else{\n                // predicted w==0 but observation suggests w>=1: lower some skills to create deficit.\n                // distribute by task requirements.\n                double sumd = 1e-9;\n                for(int k=0;k<K;k++) sumd += d[task][k] + 1.0;\n                for(int k=0;k<K;k++){\n                    double frac = (d[task][k] + 1.0) / sumd;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }\n        }\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const int CKEY = 180;\n    const int CAGE = 80;\n\n    for(int day=1; day<=2000; day++){\n        // free members\n        vector<int> free_m;\n        free_m.reserve(M);\n        for(int j=0;j<M;j++) if(member_task[j]==-1) free_m.push_back(j);\n        shuffle(free_m.begin(), free_m.end(), rng);\n\n        // collect candidate tasks from pq_key and pq_age\n        vector<int> cand;\n        cand.reserve(CKEY + CAGE + 20);\n        vector<char> in_cand(N, 0);\n\n        vector<pair<long long,int>> popped_key, popped_age;\n        popped_key.reserve(CKEY*2);\n        popped_age.reserve(CAGE*2);\n\n        auto collect_from = [&](auto &pq, int C, vector<pair<long long,int>> &popped){\n            while(!pq.empty() && (int)cand.size() < CKEY + CAGE){\n                auto top = pq.top(); pq.pop();\n                popped.push_back(top);\n                int t = top.second;\n                if(state[t]!=0) continue;\n                if(indeg[t]!=0) continue;\n                if(!in_ready[t]) continue;\n                if(in_cand[t]) continue;\n                in_cand[t]=1;\n                cand.push_back(t);\n                if((int)cand.size() >= C) break;\n            }\n        };\n\n        collect_from(pq_key, CKEY, popped_key);\n        collect_from(pq_age, CKEY + CAGE, popped_age); // total bound via cand size\n\n        // If no candidates or no free members -> output 0\n        vector<pair<int,int>> assigns;\n\n        if(!free_m.empty() && !cand.empty()){\n            struct PairScore{\n                double s;\n                int mem;\n                int task;\n            };\n            vector<PairScore> pairs;\n            pairs.reserve((int)free_m.size() * (int)cand.size());\n\n            for(int mem: free_m){\n                for(int task: cand){\n                    double pt = predict_time(task, mem);\n\n                    // Task priority component\n                    double pr = (double)cp[task]\n                              + 0.03 * (double)outdeg[task]\n                              + 0.001 * (double)diff[task];\n\n                    // age bonus to avoid long tail\n                    double age = (double)(day - ready_since[task]);\n                    double age_bonus = 0.0008 * age;\n\n                    // exploration bonus for less-sampled members\n                    double explore_bonus = 0.02 / sqrt(1.0 + samples[mem]);\n\n                    // final desirability: critical tasks, fast member fit\n                    double score = pr / pow(pt, 0.85) + age_bonus + explore_bonus;\n                    pairs.push_back({score, mem, task});\n                }\n            }\n\n            sort(pairs.begin(), pairs.end(), [&](const PairScore& a, const PairScore& b){\n                return a.s > b.s;\n            });\n\n            vector<char> used_mem(M, 0), used_task(N, 0);\n            for(auto &p: pairs){\n                if(used_mem[p.mem]) continue;\n                if(used_task[p.task]) continue;\n                // assign\n                used_mem[p.mem] = 1;\n                used_task[p.task] = 1;\n                assigns.push_back({p.mem, p.task});\n\n                state[p.task] = 1;\n                member_task[p.mem] = p.task;\n                member_start[p.mem] = day;\n                in_ready[p.task] = 0;\n\n                if((int)assigns.size() == (int)free_m.size()) break;\n            }\n        }\n\n        // re-push popped PQ entries if still relevant and not assigned today\n        vector<char> assigned_today(N, 0);\n        for(auto [m,t]: assigns) assigned_today[t] = 1;\n\n        for(auto &e: popped_key){\n            int t = e.second;\n            if(state[t]==0 && indeg[t]==0 && in_ready[t] && !assigned_today[t]){\n                pq_key.push(e);\n            }\n        }\n        for(auto &e: popped_age){\n            int t = e.second;\n            if(state[t]==0 && indeg[t]==0 && in_ready[t] && !assigned_today[t]){\n                pq_age.push(e);\n            }\n        }\n\n        // output assignments\n        cout << assigns.size();\n        for(auto [mem, task]: assigns){\n            cout << ' ' << (mem+1) << ' ' << (task+1);\n        }\n        cout << '\\n' << flush;\n\n        // input finished members\n        int nfin;\n        cin >> nfin;\n        if(nfin == -1) return 0;\n\n        for(int i=0;i<nfin;i++){\n            int f; cin >> f; --f;\n            int task = member_task[f];\n            int st = member_start[f];\n            int t_obs = day - st + 1;\n\n            update_skill_interval(f, task, t_obs);\n            samples[f]++;\n\n            member_task[f] = -1;\n            member_start[f] = -1;\n\n            state[task] = 2;\n\n            for(int v: g[task]){\n                indeg[v]--;\n                if(indeg[v]==0 && state[v]==0){\n                    ready_since[v] = day; // became ready at end of this day\n                    push_ready(v, day);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Order { int ax, ay, cx, cy; };\nstruct Point { int x, y; };\nstatic inline int distMan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\nstatic const Point OFFICE{400, 400};\n\nstruct Node {\n    int id;\n    uint8_t tp; // 0 pickup, 1 delivery\n};\n\nstruct RNG {\n    uint64_t s;\n    explicit RNG(uint64_t seed) : s(seed) {}\n    static inline uint64_t splitmix64(uint64_t &x) {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    inline uint64_t next_u64() { return splitmix64(s); }\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct BestState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    int cost = INT_MAX;\n};\n\nstruct CurState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    array<Point,102> pts{}; // OFFICE + 100 nodes + OFFICE\n    int cost = INT_MAX;\n\n    array<int,1000> pickPos;\n    array<int,1000> delPos;\n    array<uint8_t,1000> selected;\n};\n\nstatic inline Point nodePoint(const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              const Node& nd) {\n    return (nd.tp == 0 ? pickPt[nd.id] : delPt[nd.id]);\n}\n\nstatic inline int computeCostFromPts(const array<Point,102>& pts) {\n    int c = 0;\n    for (int i = 0; i < 101; i++) c += distMan(pts[i], pts[i+1]);\n    return c;\n}\n\nstatic void buildPtsAndPos(CurState& st,\n                           const array<Point,1000>& pickPt,\n                           const array<Point,1000>& delPt) {\n    st.pts[0] = OFFICE;\n    for (int i = 0; i < 100; i++) st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[101] = OFFICE;\n    st.cost = computeCostFromPts(st.pts);\n\n    st.pickPos.fill(-1);\n    st.delPos.fill(-1);\n    for (int i = 0; i < 100; i++) {\n        const Node &nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n}\n\nstatic array<Node,100> buildGreedyInterleaving(const array<Point,1000>& pickPt,\n                                               const array<Point,1000>& delPt,\n                                               const array<int,50>& sel) {\n    vector<int> unpicked; unpicked.reserve(50);\n    for (int i = 0; i < 50; i++) unpicked.push_back(sel[i]);\n    vector<int> carrying; carrying.reserve(50);\n\n    array<Node,100> seq;\n    Point cur = OFFICE;\n\n    auto erase_by_swap_back = [](vector<int>& v, int idx) {\n        v[idx] = v.back();\n        v.pop_back();\n    };\n\n    for (int t = 0; t < 100; t++) {\n        int bestDist = INT_MAX, bestId = -1, bestType = -1, bestIdx = -1;\n\n        for (int i = 0; i < (int)unpicked.size(); i++) {\n            int id = unpicked[i];\n            int d = distMan(cur, pickPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 0; bestIdx = i; }\n        }\n        for (int i = 0; i < (int)carrying.size(); i++) {\n            int id = carrying[i];\n            int d = distMan(cur, delPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 1; bestIdx = i; }\n        }\n\n        if (bestType == 0) {\n            seq[t] = Node{bestId, 0};\n            cur = pickPt[bestId];\n            carrying.push_back(bestId);\n            erase_by_swap_back(unpicked, bestIdx);\n        } else {\n            seq[t] = Node{bestId, 1};\n            cur = delPt[bestId];\n            erase_by_swap_back(carrying, bestIdx);\n        }\n    }\n    return seq;\n}\n\n// Best insertion of pickup+delivery into base sequence (size L), pickup before delivery.\nstatic pair<vector<Node>, int> bestInsertPairFast(const vector<Node>& base,\n                                                  const Point& pick,\n                                                  const Point& del,\n                                                  int idToInsert,\n                                                  const array<Point,1000>& pickPt,\n                                                  const array<Point,1000>& delPt) {\n    const int L = (int)base.size();\n\n    vector<Point> pts(L + 2);\n    pts[0] = OFFICE;\n    for (int i = 0; i < L; i++) pts[i+1] = nodePoint(pickPt, delPt, base[i]);\n    pts[L+1] = OFFICE;\n\n    int baseCost = 0;\n    for (int i = 0; i < L+1; i++) baseCost += distMan(pts[i], pts[i+1]);\n\n    int bestDelta = INT_MAX;\n    int bestP = 0;\n    int bestD = 1;\n\n    for (int p = 0; p <= L; p++) {\n        int delta1 = distMan(pts[p], pick) + distMan(pick, pts[p+1]) - distMan(pts[p], pts[p+1]);\n\n        for (int dpos = p+1; dpos <= L+1; dpos++) {\n            Point left, right;\n            if (dpos == p+1) {\n                left = pick;\n                right = pts[p+1];\n            } else {\n                left = pts[dpos-1];\n                right = pts[dpos];\n            }\n            int delta2 = distMan(left, del) + distMan(del, right) - distMan(left, right);\n            int tot = delta1 + delta2;\n            if (tot < bestDelta) {\n                bestDelta = tot;\n                bestP = p;\n                bestD = dpos;\n            }\n        }\n    }\n\n    vector<Node> res = base;\n    res.insert(res.begin() + bestP, Node{idToInsert, 0});\n    res.insert(res.begin() + bestD, Node{idToInsert, 1});\n    int newCost = baseCost + bestDelta;\n    return {res, newCost};\n}\n\nstatic pair<array<Node,100>, int> buildCheapestInsertionRoute(const array<int,50>& sel,\n                                                              vector<int> orderIds,\n                                                              const array<Point,1000>& pickPt,\n                                                              const array<Point,1000>& delPt) {\n    vector<Node> nodes;\n    nodes.reserve(100);\n    int cost = 0;\n    for (int id : orderIds) {\n        auto [nn, nc] = bestInsertPairFast(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n        nodes = move(nn);\n        cost = nc;\n    }\n    array<Node,100> seq;\n    for (int i = 0; i < 100; i++) seq[i] = nodes[i];\n    return {seq, cost};\n}\n\nstatic inline void applyRelocate(array<Node,100>& a, int i, int j) {\n    if (i == j) return;\n    Node tmp = a[i];\n    if (i < j) {\n        for (int k = i; k < j; k++) a[k] = a[k+1];\n        a[j] = tmp;\n    } else {\n        for (int k = i; k > j; k--) a[k] = a[k-1];\n        a[j] = tmp;\n    }\n}\n\nstatic inline int deltaSwapPts(const array<Point,102>& pts, int i, int j) {\n    int a = i + 1, b = j + 1;\n    auto getPt = [&](int idx)->Point {\n        if (idx == a) return pts[b];\n        if (idx == b) return pts[a];\n        return pts[idx];\n    };\n\n    int edges[4] = {a-1, a, b-1, b};\n    sort(edges, edges+4);\n    int oldc = 0, newc = 0;\n    int last = -999;\n    for (int k = 0; k < 4; k++) {\n        int e = edges[k];\n        if (e == last) continue;\n        last = e;\n        if (0 <= e && e <= 100) {\n            oldc += distMan(pts[e], pts[e+1]);\n            newc += distMan(getPt(e), getPt(e+1));\n        }\n    }\n    return newc - oldc;\n}\n\nstatic inline int deltaRelocatePts(const array<Point,102>& pts, int i, int j) {\n    const Point& X = pts[i+1];\n    const Point& A = pts[i];\n    const Point& B = pts[i+2];\n    int delta_rem = distMan(A, B) - distMan(A, X) - distMan(X, B);\n\n    Point C, D;\n    if (i < j) { C = pts[j+1]; D = pts[j+2]; }\n    else { C = pts[j]; D = pts[j+1]; }\n    int delta_ins = distMan(C, X) + distMan(X, D) - distMan(C, D);\n    return delta_rem + delta_ins;\n}\n\nstatic inline bool canRelocateOrderConstraint(const CurState& st, int i, int j) {\n    const Node& nd = st.seq[i];\n    int id = nd.id;\n    int p = st.pickPos[id];\n    int d = st.delPos[id];\n    int other = (nd.tp == 0 ? d : p);\n\n    int new_other = other;\n    if (i < j) {\n        if (other >= i + 1 && other <= j) new_other = other - 1;\n    } else {\n        if (other >= j && other <= i - 1) new_other = other + 1;\n    }\n\n    if (nd.tp == 0) return j < new_other;\n    else return new_other < j;\n}\n\nstatic inline bool canSwapOrderConstraint(const CurState& st, int i, int j) {\n    const Node& a = st.seq[i];\n    const Node& b = st.seq[j];\n    if (a.id == b.id) return false;\n\n    {\n        int id = a.id;\n        int np = (a.tp == 0 ? j : st.pickPos[id]);\n        int nd = (a.tp == 1 ? j : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    {\n        int id = b.id;\n        int np = (b.tp == 0 ? i : st.pickPos[id]);\n        int nd = (b.tp == 1 ? i : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    return true;\n}\n\nstatic void updateRangeAfterRelocate(CurState& st,\n                                     const array<Point,1000>& pickPt,\n                                     const array<Point,1000>& delPt,\n                                     int l, int r) {\n    for (int k = l; k <= r; k++) {\n        st.pts[k+1] = nodePoint(pickPt, delPt, st.seq[k]);\n        const Node& nd = st.seq[k];\n        if (nd.tp == 0) st.pickPos[nd.id] = k;\n        else st.delPos[nd.id] = k;\n    }\n}\n\nstatic void updateAfterSwap(CurState& st,\n                            const array<Point,1000>& pickPt,\n                            const array<Point,1000>& delPt,\n                            int i, int j) {\n    st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[j+1] = nodePoint(pickPt, delPt, st.seq[j]);\n    {\n        const Node& nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n    {\n        const Node& nd = st.seq[j];\n        if (nd.tp == 0) st.pickPos[nd.id] = j;\n        else st.delPos[nd.id] = j;\n    }\n}\n\nstatic vector<Node> baseWithoutPositions(const array<Node,100>& seq, const vector<int>& posToSkip) {\n    array<uint8_t,100> skip{};\n    skip.fill(0);\n    for (int p : posToSkip) skip[p] = 1;\n    vector<Node> base;\n    base.reserve(100 - (int)posToSkip.size());\n    for (int i = 0; i < 100; i++) if (!skip[i]) base.push_back(seq[i]);\n    return base;\n}\n\nstatic void greedyImproveRelocate(CurState& st,\n                                  const array<Point,1000>& pickPt,\n                                  const array<Point,1000>& delPt,\n                                  RNG& rng,\n                                  int iters) {\n    for (int it = 0; it < iters; it++) {\n        int i = rng.next_int(0, 99);\n        int j = rng.next_int(0, 99);\n        if (i == j) continue;\n        if (!canRelocateOrderConstraint(st, i, j)) continue;\n\n        int delta = deltaRelocatePts(st.pts, i, j);\n        if (delta >= 0) continue;\n\n        applyRelocate(st.seq, i, j);\n        int l = min(i, j), r = max(i, j);\n        updateRangeAfterRelocate(st, pickPt, delPt, l, r);\n        st.cost += delta;\n    }\n}\n\nstatic void hillClimbOrderReinsert(CurState& st,\n                                   const array<Point,1000>& pickPt,\n                                   const array<Point,1000>& delPt,\n                                   RNG& rng,\n                                   int attempts) {\n    for (int t = 0; t < attempts; t++) {\n        int idx = rng.next_int(0, 49);\n        int id = st.sel[idx];\n        int pi = st.pickPos[id], di = st.delPos[id];\n        if (!(0 <= pi && pi < di && di < 100)) continue;\n\n        vector<Node> base = baseWithoutPositions(st.seq, {pi, di});\n        auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[id], delPt[id], id, pickPt, delPt);\n        if (newCost < st.cost) {\n            for (int i = 0; i < 100; i++) st.seq[i] = newNodes[i];\n            buildPtsAndPos(st, pickPt, delPt);\n        }\n    }\n}\n\nstatic array<int,50> sampleSelBiased(const vector<int>& pool, RNG& rng, const vector<double>& cdf) {\n    array<int,50> sel;\n    array<uint8_t,1000> used{}; used.fill(0);\n    double sum = cdf.back();\n    for (int k = 0; k < 50; k++) {\n        while (true) {\n            double r = rng.next_double() * sum;\n            int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n            idx = max(0, min(idx, (int)pool.size() - 1));\n            int id = pool[idx];\n            if (!used[id]) { used[id] = 1; sel[k] = id; break; }\n        }\n    }\n    return sel;\n}\n\nstatic array<int,50> sampleSelCluster(const array<Point,1000>& pickPt,\n                                      const array<Point,1000>& delPt,\n                                      RNG& rng,\n                                      const Point& center) {\n    vector<pair<int,int>> v;\n    v.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int cp = distMan(center, pickPt[i]);\n        int cd = distMan(center, delPt[i]);\n        int pd = distMan(pickPt[i], delPt[i]);\n        int op = distMan(OFFICE, pickPt[i]);\n        int od = distMan(OFFICE, delPt[i]);\n        int score = (cp + cd) * 100 + pd * 28 + (op + od) * 10;\n        v.push_back({score, i});\n    }\n    nth_element(v.begin(), v.begin() + 50, v.end());\n    v.resize(50);\n    array<int,50> sel;\n    for (int i = 0; i < 50; i++) sel[i] = v[i].second;\n    return sel;\n}\n\nstatic CurState buildStateFromSelTryConstructors(const array<int,50>& sel,\n                                                const array<Point,1000>& pickPt,\n                                                const array<Point,1000>& delPt,\n                                                RNG& rng) {\n    CurState st;\n    st.sel = sel;\n    st.selected.fill(0);\n    for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n\n    // A) greedy interleaving\n    array<Node,100> bestSeq = buildGreedyInterleaving(pickPt, delPt, st.sel);\n    CurState tmp;\n    tmp.sel = st.sel; tmp.seq = bestSeq; tmp.selected = st.selected;\n    buildPtsAndPos(tmp, pickPt, delPt);\n    int bestCost = tmp.cost;\n\n    // B) cheapest insertion far-first\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            int da = distMan(OFFICE, pickPt[a]) + distMan(OFFICE, delPt[a]);\n            int db = distMan(OFFICE, pickPt[b]) + distMan(OFFICE, delPt[b]);\n            return da > db;\n        });\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n    // C) cheapest insertion random\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        shuffle(ids.begin(), ids.end(), std::mt19937((uint32_t)rng.next_u64()));\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n\n    st.seq = bestSeq;\n    buildPtsAndPos(st, pickPt, delPt);\n    return st;\n}\n\n// Heuristic \"badness\" per selected order: sum of 4 incident edges around pickup+delivery nodes\nstatic inline int orderIncidentCost(const CurState& st, int id) {\n    int p = st.pickPos[id], d = st.delPos[id];\n    if (!(0 <= p && p < d && d < 100)) return INT_MAX/4;\n    auto edgeSumAtPos = [&](int pos)->int {\n        // node at pos => point index pos+1. incident edges are (pos,pos+1) and (pos+1,pos+2) in pts indices\n        int idx = pos + 1;\n        return distMan(st.pts[idx-1], st.pts[idx]) + distMan(st.pts[idx], st.pts[idx+1]);\n    };\n    return edgeSumAtPos(p) + edgeSumAtPos(d);\n}\n\n// Pick k distinct sel indices, biased toward worse orders\nstatic vector<int> pickKOutIndices(const CurState& st, RNG& rng, int k) {\n    vector<pair<int,int>> v;\n    v.reserve(50);\n    for (int i = 0; i < 50; i++) {\n        int id = st.sel[i];\n        v.push_back({orderIncidentCost(st, id), i});\n    }\n    sort(v.begin(), v.end(), greater<>());\n    int cand = min(20, (int)v.size());\n    vector<int> out;\n    out.reserve(k);\n    array<uint8_t,50> used{}; used.fill(0);\n    while ((int)out.size() < k) {\n        int idx = rng.next_int(0, cand-1);\n        int si = v[idx].second;\n        if (!used[si]) { used[si] = 1; out.push_back(si); }\n    }\n    return out;\n}\n\n// Route-only LNS: remove k orders and reinsert them (repair).\nstatic bool moveRouteLNS_k(CurState& cur,\n                           const array<Point,1000>& pickPt,\n                           const array<Point,1000>& delPt,\n                           RNG& rng,\n                           int k,\n                           double temp) {\n    auto outIdx = pickKOutIndices(cur, rng, k);\n    vector<int> outIds; outIds.reserve(k);\n    vector<int> skipPos; skipPos.reserve(2*k);\n\n    for (int si : outIdx) {\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 2*k) return false;\n\n    vector<Node> base = baseWithoutPositions(cur.seq, skipPos);\n\n    // Try two insertion orders: far-first and random\n    auto eval_order = [&](vector<int> ids)->pair<vector<Node>, int> {\n        vector<Node> nodes = base;\n        int cost = INT_MAX;\n        for (int id : ids) {\n            auto res = bestInsertPairFast(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n            nodes = move(res.first);\n            cost = res.second;\n        }\n        return {nodes, cost};\n    };\n\n    vector<int> ids1 = outIds;\n    sort(ids1.begin(), ids1.end(), [&](int a, int b) {\n        int da = distMan(OFFICE, pickPt[a]) + distMan(OFFICE, delPt[a]);\n        int db = distMan(OFFICE, pickPt[b]) + distMan(OFFICE, delPt[b]);\n        return da > db;\n    });\n    auto [nodesA, costA] = eval_order(ids1);\n\n    vector<int> ids2 = outIds;\n    shuffle(ids2.begin(), ids2.end(), std::mt19937((uint32_t)rng.next_u64()));\n    auto [nodesB, costB] = eval_order(ids2);\n\n    int newCost = min(costA, costB);\n    const vector<Node>* bestNodes = (costA <= costB ? &nodesA : &nodesB);\n\n    int delta = newCost - cur.cost;\n    bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n    if (!accept) return false;\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = (*bestNodes)[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    return true;\n}\n\n// Selection LNS: swap out k orders and swap in k new ones, then repair route by cheapest insertion.\nstatic bool moveSelectionLNS_k(CurState& cur,\n                               const vector<int>& pool,\n                               const array<Point,1000>& pickPt,\n                               const array<Point,1000>& delPt,\n                               RNG& rng,\n                               int k,\n                               double temp) {\n    auto outIdx = pickKOutIndices(cur, rng, k);\n    vector<int> outIds; outIds.reserve(k);\n    vector<int> skipPos; skipPos.reserve(2*k);\n\n    for (int si : outIdx) {\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 2*k) return false;\n\n    vector<int> inIds; inIds.reserve(k);\n    array<uint8_t,1000> forbidden = cur.selected;\n    for (int id : outIds) forbidden[id] = 1; // to avoid re-adding same removed id immediately\n    for (int t = 0; t < k; t++) {\n        int inId = -1;\n        for (int tries = 0; tries < 100; tries++) {\n            int cand = pool[rng.next_int(0, (int)pool.size()-1)];\n            if (!forbidden[cand]) { inId = cand; break; }\n        }\n        if (inId == -1) return false;\n        forbidden[inId] = 1;\n        inIds.push_back(inId);\n    }\n\n    vector<Node> base = baseWithoutPositions(cur.seq, skipPos);\n\n    // Insert new orders (try far-first)\n    vector<int> ids = inIds;\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        int da = distMan(OFFICE, pickPt[a]) + distMan(OFFICE, delPt[a]);\n        int db = distMan(OFFICE, pickPt[b]) + distMan(OFFICE, delPt[b]);\n        return da > db;\n    });\n\n    vector<Node> nodes = base;\n    int cost = INT_MAX;\n    for (int id : ids) {\n        auto res = bestInsertPairFast(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n        nodes = move(res.first);\n        cost = res.second;\n    }\n\n    int newCost = cost;\n    int delta = newCost - cur.cost;\n    bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n    if (!accept) return false;\n\n    // apply selection change\n    for (int t = 0; t < k; t++) {\n        int si = outIdx[t];\n        int outId = cur.sel[si];\n        int inId = inIds[t];\n        cur.selected[outId] = 0;\n        cur.selected[inId] = 1;\n        cur.sel[si] = inId;\n    }\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = nodes[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> ord(1000);\n    for (int i = 0; i < 1000; i++) cin >> ord[i].ax >> ord[i].ay >> ord[i].cx >> ord[i].cy;\n\n    array<Point,1000> pickPt, delPt;\n    for (int i = 0; i < 1000; i++) {\n        pickPt[i] = Point{ord[i].ax, ord[i].ay};\n        delPt[i]  = Point{ord[i].cx, ord[i].cy};\n    }\n\n    // Deterministic seed from input hash (robustness)\n    uint64_t h = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) {\n        h ^= v;\n        h *= 1099511628211ULL;\n    };\n    for (int i = 0; i < 1000; i++) {\n        mix((uint64_t)ord[i].ax);\n        mix((uint64_t)ord[i].ay);\n        mix((uint64_t)ord[i].cx);\n        mix((uint64_t)ord[i].cy);\n    }\n    RNG rng(h ^ 0x9e3779b97f4a7c15ULL);\n\n    vector<pair<int,int>> solo;\n    solo.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int c = distMan(OFFICE, pickPt[i]) + distMan(pickPt[i], delPt[i]) + distMan(delPt[i], OFFICE);\n        solo.push_back({c, i});\n    }\n    sort(solo.begin(), solo.end());\n\n    int POOL = 900;\n    vector<int> pool; pool.reserve(POOL);\n    for (int i = 0; i < min(POOL, 1000); i++) pool.push_back(solo[i].second);\n\n    const double alpha = 1.15;\n    vector<double> cdf(pool.size());\n    double acc = 0.0;\n    for (int i = 0; i < (int)pool.size(); i++) {\n        double w = 1.0 / pow((double)(i + 1), alpha);\n        acc += w;\n        cdf[i] = acc;\n    }\n\n    auto t0 = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - t0).count();\n    };\n\n    const double INIT_LIMIT = 0.28;\n    const double SA_LIMIT   = 1.92;\n    const double DEADLINE   = 1.985;\n\n    // Initialization (multi-start)\n    BestState initBest;\n    {\n        array<int,50> sel0;\n        for (int i = 0; i < 50; i++) sel0[i] = solo[i].second;\n        CurState st = buildStateFromSelTryConstructors(sel0, pickPt, delPt, rng);\n        greedyImproveRelocate(st, pickPt, delPt, rng, 2200);\n        hillClimbOrderReinsert(st, pickPt, delPt, rng, 20);\n        initBest.cost = st.cost;\n        initBest.sel = st.sel;\n        initBest.seq = st.seq;\n\n        int restarts = 0;\n        while (elapsedSec() < INIT_LIMIT && restarts < 16) {\n            array<int,50> sel;\n            if (restarts < 10) {\n                sel = sampleSelBiased(pool, rng, cdf);\n            } else {\n                int baseId = rng.next_int(0, 999);\n                Point center = (rng.next_int(0, 1) ? pickPt[baseId] : delPt[baseId]);\n                if (rng.next_double() < 0.40) {\n                    Point corner{ (rng.next_int(0,1)?0:800), (rng.next_int(0,1)?0:800) };\n                    center.x = (center.x + corner.x) / 2;\n                    center.y = (center.y + corner.y) / 2;\n                }\n                sel = sampleSelCluster(pickPt, delPt, rng, center);\n            }\n\n            CurState st2 = buildStateFromSelTryConstructors(sel, pickPt, delPt, rng);\n            greedyImproveRelocate(st2, pickPt, delPt, rng, 1600);\n            hillClimbOrderReinsert(st2, pickPt, delPt, rng, 20);\n\n            if (st2.cost < initBest.cost) {\n                initBest.cost = st2.cost;\n                initBest.sel = st2.sel;\n                initBest.seq = st2.seq;\n            }\n            restarts++;\n        }\n    }\n\n    CurState cur;\n    cur.sel = initBest.sel;\n    cur.seq = initBest.seq;\n    cur.selected.fill(0);\n    for (int i = 0; i < 50; i++) cur.selected[cur.sel[i]] = 1;\n    buildPtsAndPos(cur, pickPt, delPt);\n\n    BestState best;\n    best.cost = cur.cost;\n    best.sel = cur.sel;\n    best.seq = cur.seq;\n\n    // SA temps\n    const double T0 = 2800.0;\n    const double T1 = 14.0;\n\n    while (elapsedSec() < SA_LIMIT) {\n        double e = elapsedSec();\n        double prog = e / SA_LIMIT;\n        double temp = T0 * pow(T1 / T0, prog);\n\n        double r = rng.next_double();\n\n        if (r < 0.55) {\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (!canRelocateOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaRelocatePts(cur.pts, i, j);\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            applyRelocate(cur.seq, i, j);\n            int l = min(i, j), rr = max(i, j);\n            updateRangeAfterRelocate(cur, pickPt, delPt, l, rr);\n            cur.cost += delta;\n\n        } else if (r < 0.70) {\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (i > j) swap(i, j);\n            if (!canSwapOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaSwapPts(cur.pts, i, j);\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            swap(cur.seq[i], cur.seq[j]);\n            swap(cur.pts[i+1], cur.pts[j+1]);\n            updateAfterSwap(cur, pickPt, delPt, i, j);\n            cur.cost += delta;\n\n        } else if (r < 0.82) {\n            // single order reinsert (same selection)\n            int idx = rng.next_int(0, 49);\n            int id = cur.sel[idx];\n            int pi = cur.pickPos[id], di = cur.delPos[id];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            vector<Node> base = baseWithoutPositions(cur.seq, {pi, di});\n            auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[id], delPt[id], id, pickPt, delPt);\n            int delta = newCost - cur.cost;\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n\n        } else if (r < 0.88) {\n            // route-only LNS (k=3)\n            if (elapsedSec() < SA_LIMIT - 0.05) {\n                moveRouteLNS_k(cur, pickPt, delPt, rng, 3, temp);\n            }\n\n        } else if (r < 0.96) {\n            // selection swap (single)\n            int outIdx = rng.next_int(0, 49);\n            int outId = cur.sel[outIdx];\n\n            int inId = -1;\n            for (int tries = 0; tries < 60; tries++) {\n                int cand = pool[rng.next_int(0, (int)pool.size() - 1)];\n                if (!cur.selected[cand]) { inId = cand; break; }\n            }\n            if (inId == -1) continue;\n\n            int pi = cur.pickPos[outId], di = cur.delPos[outId];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            vector<Node> base = baseWithoutPositions(cur.seq, {pi, di});\n            auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[inId], delPt[inId], inId, pickPt, delPt);\n            int delta = newCost - cur.cost;\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            cur.selected[outId] = 0;\n            cur.selected[inId] = 1;\n            cur.sel[outIdx] = inId;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n            greedyImproveRelocate(cur, pickPt, delPt, rng, 250);\n\n        } else {\n            // selection LNS (k=3)\n            if (elapsedSec() < SA_LIMIT - 0.07) {\n                moveSelectionLNS_k(cur, pool, pickPt, delPt, rng, 3, temp);\n            }\n        }\n\n        if (cur.cost < best.cost) {\n            best.cost = cur.cost;\n            best.sel = cur.sel;\n            best.seq = cur.seq;\n        }\n    }\n\n    // Final polish\n    {\n        CurState st;\n        st.sel = best.sel;\n        st.seq = best.seq;\n        st.selected.fill(0);\n        for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n        buildPtsAndPos(st, pickPt, delPt);\n\n        while (elapsedSec() < DEADLINE) {\n            hillClimbOrderReinsert(st, pickPt, delPt, rng, 25);\n            greedyImproveRelocate(st, pickPt, delPt, rng, 900);\n            if (st.cost < best.cost) {\n                best.cost = st.cost;\n                best.sel = st.sel;\n                best.seq = st.seq;\n            } else break;\n        }\n    }\n\n    // Output\n    cout << 50;\n    for (int i = 0; i < 50; i++) cout << \" \" << (best.sel[i] + 1);\n    cout << \"\\n\";\n\n    vector<Point> path;\n    path.reserve(102);\n    path.push_back(OFFICE);\n    for (int i = 0; i < 100; i++) path.push_back(nodePoint(pickPt, delPt, best.seq[i]));\n    path.push_back(OFFICE);\n\n    vector<Point> comp;\n    comp.reserve(path.size());\n    for (auto &p : path) {\n        if (comp.empty() || comp.back().x != p.x || comp.back().y != p.y) comp.push_back(p);\n    }\n\n    cout << (int)comp.size();\n    for (auto &p : comp) cout << \" \" << p.x << \" \" << p.y;\n    cout << \"\\n\";\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <atcoder/all>\n\nusing namespace std;\nusing atcoder::dsu;\n\n// ---------- HLD for max on path (edge values stored on child node positions) ----------\nstruct HLD {\n    int n;\n    vector<vector<pair<int,int>>> g; // to, edgeIndexInMSTAdj(not needed) ; we'll store edge id separately elsewhere\n    vector<int> parent, depth, heavy, head, pos, sz;\n    vector<int> parEdgeD; // d of edge to parent (root=0)\n    vector<int> parEdgeIdx; // original input index of edge to parent (root=-1)\n    int cur;\n\n    HLD(int n=0): n(n) {}\n\n    void build_from_tree(const vector<vector<tuple<int,int,int>>>& tree, int root=0) {\n        // tree[v]: (to, d, inputEdgeIndex)\n        n = (int)tree.size();\n        g.assign(n, {});\n        // We'll keep full info in temporary adjacency\n        // We'll do DFS with that adjacency; no need to fill g.\n        parent.assign(n, -1);\n        depth.assign(n, 0);\n        heavy.assign(n, -1);\n        head.assign(n, 0);\n        pos.assign(n, 0);\n        sz.assign(n, 0);\n        parEdgeD.assign(n, 0);\n        parEdgeIdx.assign(n, -1);\n\n        // Rooting DFS to set parent/depth/parEdge*\n        vector<int> st = {root};\n        parent[root] = -1;\n        depth[root] = 0;\n        vector<int> order;\n        order.reserve(n);\n        while(!st.empty()){\n            int v = st.back(); st.pop_back();\n            order.push_back(v);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                parent[to] = v;\n                depth[to] = depth[v] + 1;\n                parEdgeD[to] = d;\n                parEdgeIdx[to] = idx;\n                st.push_back(to);\n            }\n        }\n        // compute sizes and heavy in reverse order\n        for (int i = (int)order.size()-1; i>=0; --i) {\n            int v = order[i];\n            sz[v] = 1;\n            int bestSize = 0;\n            int bestChild = -1;\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v]) continue;\n                sz[v] += sz[to];\n                if (sz[to] > bestSize) {\n                    bestSize = sz[to];\n                    bestChild = to;\n                }\n            }\n            heavy[v] = bestChild;\n        }\n\n        // decompose\n        cur = 0;\n        function<void(int,int)> decomp = [&](int v, int h) {\n            head[v] = h;\n            pos[v] = cur++;\n            if (heavy[v] != -1) decomp(heavy[v], h);\n            for (auto [to, d, idx] : tree[v]) {\n                if (to == parent[v] || to == heavy[v]) continue;\n                decomp(to, to);\n            }\n        };\n        decomp(root, root);\n    }\n\n    template<class Seg>\n    int query_max(int a, int b, Seg &seg) const {\n        int res = 0;\n        int u=a, v=b;\n        while (head[u] != head[v]) {\n            if (depth[head[u]] < depth[head[v]]) swap(u, v);\n            // include head[u] position (its edge to parent is part of path except when head is root; root has 0)\n            res = max(res, seg.prod(pos[head[u]], pos[u] + 1));\n            u = parent[head[u]];\n        }\n        if (depth[u] > depth[v]) swap(u, v);\n        // u is LCA; exclude pos[u] (edge to parent of LCA not on path)\n        res = max(res, seg.prod(pos[u] + 1, pos[v] + 1));\n        return res;\n    }\n};\n\n// segtree for max<int>\nint op_max(int a, int b){ return max(a,b); }\nint e_max(){ return 0; }\n\n// ---------- main ----------\nstatic inline int rounded_dist(int x1,int y1,int x2,int y2){\n    long long dx = x1 - x2;\n    long long dy = y1 - y2;\n    double dist = std::sqrt((double)dx*dx + (double)dy*dy);\n    return (int)llround(dist);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 400;\n    const int M = 1995;\n\n    vector<int> x(N), y(N);\n    for(int i=0;i<N;i++){\n        if(!(cin >> x[i] >> y[i])) return 0;\n    }\n    vector<int> U(M), V(M);\n    for(int i=0;i<M;i++){\n        cin >> U[i] >> V[i];\n    }\n\n    vector<int> D(M);\n    for(int i=0;i<M;i++){\n        D[i] = rounded_dist(x[U[i]], y[U[i]], x[V[i]], y[V[i]]);\n        if (D[i] < 0) D[i] = 0;\n    }\n\n    // Build MST on given edges using weight D[i] (guidance only)\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        if (D[a] != D[b]) return D[a] < D[b];\n        if (U[a] != U[b]) return U[a] < U[b];\n        if (V[a] != V[b]) return V[a] < V[b];\n        return a < b;\n    });\n\n    dsu dsu_mst(N);\n    vector<char> inMST(M, false);\n    vector<vector<tuple<int,int,int>>> tree(N); // to, d, inputIndex\n    int picked = 0;\n    for(int idx: ord){\n        if (picked == N-1) break;\n        int u=U[idx], v=V[idx];\n        if(dsu_mst.same(u,v)) continue;\n        dsu_mst.merge(u,v);\n        inMST[idx]=true;\n        picked++;\n        tree[u].push_back({v, D[idx], idx});\n        tree[v].push_back({u, D[idx], idx});\n    }\n    // (Graph guaranteed connected, so picked==N-1)\n\n    // Build HLD + segtree on this MST\n    HLD hld;\n    hld.build_from_tree(tree, 0);\n\n    // map input edge index -> child node in rooted MST (for updates)\n    vector<int> idxToChild(M, -1);\n    for(int v=1; v<N; v++){\n        int idx = hld.parEdgeIdx[v];\n        if(idx >= 0) idxToChild[idx] = v;\n    }\n\n    vector<int> init(N, 0);\n    for(int v=1; v<N; v++){\n        init[hld.pos[v]] = hld.parEdgeD[v]; // edge value on child position\n    }\n    atcoder::segtree<int, op_max, e_max> seg(init);\n\n    // Adopted forest DSU\n    dsu dsu_acc(N);\n    vector<pair<int,int>> adopted;\n    adopted.reserve(N-1);\n    int comps = N;\n\n    auto can_reject = [&](int i)->bool{\n        dsu tmp(N);\n        for(auto &e: adopted) tmp.merge(e.first, e.second);\n        for(int j=i+1;j<M;j++){\n            tmp.merge(U[j], V[j]);\n        }\n        return tmp.size(0) == N;\n    };\n\n    for(int i=0;i<M;i++){\n        int l;\n        if(!(cin >> l)) break;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        if (comps == 1) {\n            ans = 0;\n        } else if (dsu_acc.same(u,v)) {\n            ans = 0; // never take cycle edges\n        } else {\n            bool okReject = can_reject(i);\n            bool take = false;\n\n            if (!okReject) {\n                take = true; // forced (bridge in remaining available graph)\n            } else {\n                // dynamic thresholds (mildly relaxed near the end / when urgent)\n                double t = (M <= 1) ? 1.0 : (double)i / (double)(M-1);\n                double remain = max(1, (M-1-i));\n                double need = comps - 1;\n                double urg = need / remain;           // ~0..>1 (cap below)\n                double mult = 1.0 + 0.8 * min(1.0, urg);\n\n                auto cap3 = [&](double r){ return min(3.0, r); };\n                int cheapR = (int)llround(cap3((1.35 + 0.35*t) * mult) * 1000.0);  // vs D[i]\n                int replR  = (int)llround(cap3((1.75 + 0.35*t) * mult) * 1000.0);  // vs md\n                int treeR  = (int)llround(cap3((2.10 + 0.30*t) * mult) * 1000.0);  // MST edges slightly looser\n\n                long long L = l;\n                long long di = D[i];\n\n                // If it's an MST edge and not too bad, often keep it.\n                if (inMST[i] && L*1000LL <= di * (long long)treeR) take = true;\n\n                // Very cheap by its own distance\n                if (!take && L*1000LL <= di * (long long)cheapR) take = true;\n\n                // Competitive compared to remaining MST bottleneck on u-v path\n                if (!take) {\n                    int md = hld.query_max(u, v, seg); // max remaining D on MST path\n                    if (md > 0) {\n                        // require di not much larger than md (di <= 1.25*md)\n                        if (di*1000LL <= (long long)md * 1250LL &&\n                            L*1000LL <= (long long)md * (long long)replR) {\n                            take = true;\n                        }\n                    }\n                }\n            }\n\n            if (take) {\n                dsu_acc.merge(u,v);\n                adopted.push_back({u,v});\n                comps--;\n                ans = 1;\n            } else {\n                ans = 0;\n            }\n        }\n\n        cout << ans << \"\\n\";\n        cout.flush();\n\n        // Remove MST edge from \"future MST edges\" structure once its index is processed\n        if (inMST[i]) {\n            int child = idxToChild[i];\n            if (child != -1) seg.set(hld.pos[child], 0);\n        }\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 30, W = 30;\nstatic constexpr int INF = 1e9;\n\nstruct Pet { int x, y, t; };\nstruct Human { int x, y; };\n\nstruct Rect { int x1, x2, y1, y2; }; // inclusive\n\nstatic inline bool inb(int x,int y){ return 1<=x && x<=H && 1<=y && y<=W; }\nstatic inline int manhattan(int ax,int ay,int bx,int by){ return abs(ax-bx)+abs(ay-by); }\n\nstatic const int dx4[4] = {-1,+1,0,0};\nstatic const int dy4[4] = {0,0,-1,+1};\nstatic const char MOVE_CH[4]  = {'U','D','L','R'};\nstatic const char BUILD_CH[4] = {'u','d','l','r'};\n\nstruct DoorInfo {\n    int x=-1,y=-1;\n    int inx=-1, iny=-1; // inside neighbor (must be in rect)\n    long long score=LLONG_MIN;\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N; cin >> N;\n    vector<Pet> pets(N);\n    for(int i=0;i<N;i++) cin >> pets[i].x >> pets[i].y >> pets[i].t;\n\n    int M; cin >> M;\n    vector<Human> humans(M);\n    for(int i=0;i<M;i++) cin >> humans[i].x >> humans[i].y;\n\n    auto inside = [&](const Rect& r, int x, int y)->bool{\n        return r.x1 <= x && x <= r.x2 && r.y1 <= y && y <= r.y2;\n    };\n\n    auto make_rect = [&](int corner, int h, int w)->Rect{\n        Rect r;\n        if(corner==0){ r.x1=1; r.x2=h; r.y1=1; r.y2=w; }                   // TL\n        if(corner==1){ r.x1=1; r.x2=h; r.y1=W-w+1; r.y2=W; }               // TR\n        if(corner==2){ r.x1=H-h+1; r.x2=H; r.y1=1; r.y2=w; }               // BL\n        if(corner==3){ r.x1=H-h+1; r.x2=H; r.y1=W-w+1; r.y2=W; }           // BR\n        return r;\n    };\n\n    auto wall_cells_for = [&](const Rect& r)->vector<pair<int,int>>{\n        vector<pair<int,int>> cells;\n        if(r.x1 > 1){\n            int x = r.x1 - 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.x2 < H){\n            int x = r.x2 + 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.y1 > 1){\n            int y = r.y1 - 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        if(r.y2 < W){\n            int y = r.y2 + 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        return cells;\n    };\n\n    auto count_pets_in_rect = [&](const Rect& r)->int{\n        int cnt=0;\n        for(auto &p: pets) if(inside(r,p.x,p.y)) cnt++;\n        return cnt;\n    };\n\n    auto dist_pet_to_rect = [&](const Rect& r)->int{\n        int best = INF;\n        for(auto &p: pets){\n            int dx = 0;\n            if(p.x < r.x1) dx = r.x1 - p.x;\n            else if(p.x > r.x2) dx = p.x - r.x2;\n            int dy = 0;\n            if(p.y < r.y1) dy = r.y1 - p.y;\n            else if(p.y > r.y2) dy = p.y - r.y2;\n            best = min(best, dx+dy);\n        }\n        return best;\n    };\n\n    auto max_human_dist_to_rect = [&](const Rect& r)->int{\n        int mx=0;\n        for(auto &hu: humans){\n            int dx=0;\n            if(hu.x < r.x1) dx = r.x1 - hu.x;\n            else if(hu.x > r.x2) dx = hu.x - r.x2;\n            int dy=0;\n            if(hu.y < r.y1) dy = r.y1 - hu.y;\n            else if(hu.y > r.y2) dy = hu.y - r.y2;\n            mx = max(mx, dx+dy);\n        }\n        return mx;\n    };\n\n    auto choose_doors = [&](const Rect& r, const vector<pair<int,int>>& wallCells, int K)->vector<DoorInfo>{\n        static bool isWall[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) isWall[x][y]=false;\n        for(auto [x,y]: wallCells) isWall[x][y]=true;\n\n        vector<DoorInfo> cand;\n        cand.reserve((int)wallCells.size());\n        for(auto [wx,wy]: wallCells){\n            int inx=-1, iny=-1;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(inb(nx,ny) && inside(r,nx,ny)){ inx=nx; iny=ny; break; }\n            }\n            if(inx==-1) continue;\n\n            bool okOutside=false;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(inside(r,nx,ny)) continue;\n                if(isWall[nx][ny]) continue;\n                okOutside=true;\n            }\n            if(!okOutside) continue;\n\n            int minPetDist = 1000;\n            for(auto &p: pets) minPetDist = min(minPetDist, manhattan(wx,wy,p.x,p.y));\n\n            long long sumHumanDist = 0;\n            for(auto &h: humans) sumHumanDist += manhattan(h.x,h.y, inx,iny);\n\n            // Slightly prefer doors not on outer border\n            int borderPenalty = (wx==1 || wx==H || wy==1 || wy==W) ? 50 : 0;\n\n            DoorInfo di;\n            di.x=wx; di.y=wy; di.inx=inx; di.iny=iny;\n            di.score = 250LL*minPetDist - 1LL*sumHumanDist - borderPenalty;\n            cand.push_back(di);\n        }\n        sort(cand.begin(), cand.end(), [&](const DoorInfo& a, const DoorInfo& b){\n            return a.score > b.score;\n        });\n\n        vector<DoorInfo> res;\n        for(auto &d: cand){\n            bool far=true;\n            for(auto &e: res){\n                if(manhattan(d.x,d.y,e.x,e.y) < 5){ far=false; break; }\n            }\n            if(!far) continue;\n            res.push_back(d);\n            if((int)res.size()>=K) break;\n        }\n        // if couldn't pick far enough, just take top\n        for(auto &d: cand){\n            if((int)res.size()>=K) break;\n            bool used=false;\n            for(auto &e: res) if(e.x==d.x && e.y==d.y) used=true;\n            if(!used) res.push_back(d);\n        }\n        return res;\n    };\n\n    // Select rectangle (more conservative: smaller, faster to build)\n    Rect bestRect{1,5,1,5};\n    vector<DoorInfo> bestDoors;\n    double bestEval = -1e100;\n\n    for(int corner=0; corner<4; corner++){\n        for(int h=5; h<=15; h++){\n            for(int w=5; w<=15; w++){\n                Rect r = make_rect(corner,h,w);\n                int area = (r.x2-r.x1+1)*(r.y2-r.y1+1);\n\n                int petsIn = count_pets_in_rect(r);\n                int minPetToRect = dist_pet_to_rect(r);\n                int maxHumanDist = max_human_dist_to_rect(r);\n\n                auto wallCells = wall_cells_for(r);\n                int wallLen = (int)wallCells.size();\n\n                // doors: 2 for longer fences, else 1\n                int K = (wallLen >= 24 ? 2 : 1);\n                auto doors = choose_doors(r, wallCells, K);\n                if((int)doors.size() < K) continue;\n\n                // must avoid initial human/pet on wall cells (too troublesome early)\n                bool bad=false;\n                for(auto [x,y]: wallCells){\n                    for(auto &p: pets) if(p.x==x && p.y==y){ bad=true; break; }\n                    if(bad) break;\n                    for(auto &hu: humans) if(hu.x==x && hu.y==y){ bad=true; break; }\n                    if(bad) break;\n                }\n                if(bad) continue;\n\n                // Heuristic evaluation (robustness-oriented)\n                double val = (double)area / 900.0;\n\n                // heavily penalize having pets initially inside\n                if(petsIn==0) val *= 1.0;\n                else val *= pow(0.5, 3.0*petsIn);\n\n                // prefer far from pets and not too far for humans\n                val *= (1.0 + 0.06 * minPetToRect);\n                val *= exp(-0.05 * maxHumanDist);\n\n                // penalize longer fences to avoid slow builds\n                val *= exp(-0.08 * wallLen);\n\n                // discourage choosing rectangles too close to pets\n                if(minPetToRect <= 1) val *= 0.2;\n\n                if(val > bestEval){\n                    bestEval = val;\n                    bestRect = r;\n                    bestDoors = doors;\n                }\n            }\n        }\n    }\n\n    Rect rect = bestRect;\n    auto wallCells = wall_cells_for(rect);\n\n    // State of blocked cells\n    static bool blocked[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) blocked[x][y]=false;\n\n    // Target wall cells to block (excluding doors)\n    static bool targetWall[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) targetWall[x][y]=false;\n    for(auto [x,y]: wallCells) targetWall[x][y]=true;\n\n    // Exclude door cells from targetWall\n    for(auto &d: bestDoors){\n        if(d.x!=-1) targetWall[d.x][d.y]=false;\n    }\n\n    vector<bool> doorClosed(bestDoors.size(), false);\n\n    // Gather point: inside, near the best door's inside neighbor, pushed deeper if possible.\n    pair<int,int> gatherPoint;\n    {\n        DoorInfo d0 = bestDoors[0];\n        int gx = d0.inx, gy = d0.iny;\n        int vx = d0.inx - d0.x;\n        int vy = d0.iny - d0.y;\n        int gx2 = gx + vx, gy2 = gy + vy;\n        if(inb(gx2,gy2) && inside(rect,gx2,gy2)){ gx=gx2; gy=gy2; }\n        gatherPoint = {gx,gy};\n    }\n\n    auto compute_occupancy = [&](vector<vector<bool>>& petAt, vector<vector<bool>>& humanAt){\n        petAt.assign(H+1, vector<bool>(W+1,false));\n        humanAt.assign(H+1, vector<bool>(W+1,false));\n        for(auto &p: pets) petAt[p.x][p.y]=true;\n        for(auto &h: humans) humanAt[h.x][h.y]=true;\n    };\n\n    auto canBuild = [&](int tx,int ty,\n                        const vector<vector<bool>>& petAt,\n                        const vector<vector<bool>>& humanAt)->bool{\n        if(!inb(tx,ty)) return false;\n        if(petAt[tx][ty] || humanAt[tx][ty]) return false;\n        for(int d=0; d<4; d++){\n            int nx=tx+dx4[d], ny=ty+dy4[d];\n            if(inb(nx,ny) && petAt[nx][ny]) return false;\n        }\n        return true;\n    };\n\n    auto bfs_dist = [&](vector<vector<int>>& dist,\n                        const vector<pair<int,int>>& sources,\n                        function<bool(int,int)> passable){\n        dist.assign(H+1, vector<int>(W+1, INF));\n        deque<pair<int,int>> q;\n        for(auto [sx,sy]: sources){\n            if(!inb(sx,sy)) continue;\n            if(!passable(sx,sy)) continue;\n            dist[sx][sy]=0;\n            q.push_back({sx,sy});\n        }\n        while(!q.empty()){\n            auto [x,y]=q.front(); q.pop_front();\n            int nd = dist[x][y]+1;\n            for(int d=0; d<4; d++){\n                int nx=x+dx4[d], ny=y+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(!passable(nx,ny)) continue;\n                if(dist[nx][ny] > nd){\n                    dist[nx][ny]=nd;\n                    q.push_back({nx,ny});\n                }\n            }\n        }\n    };\n\n    auto step_by_dist = [&](int x,int y, const vector<vector<int>>& dist,\n                            function<bool(int,int)> passable,\n                            function<int(int,int)> tiePenalty)->char{\n        int cur = dist[x][y];\n        int bestDir=-1;\n        int bestD=cur;\n        int bestPen=INF;\n        for(int d=0; d<4; d++){\n            int nx=x+dx4[d], ny=y+dy4[d];\n            if(!inb(nx,ny)) continue;\n            if(!passable(nx,ny)) continue;\n            if(dist[nx][ny] < bestD){\n                bestD = dist[nx][ny];\n                bestPen = tiePenalty(nx,ny);\n                bestDir = d;\n            }else if(dist[nx][ny] == bestD && bestDir!=-1){\n                int pen = tiePenalty(nx,ny);\n                if(pen < bestPen){\n                    bestPen = pen;\n                    bestDir = d;\n                }\n            }\n        }\n        if(bestDir==-1 || bestD>=cur) return '.';\n        return MOVE_CH[bestDir];\n    };\n\n    for(int turn=0; turn<300; turn++){\n        vector<vector<bool>> petAt, humanAt;\n        compute_occupancy(petAt, humanAt);\n\n        auto insideNow = [&](int x,int y){ return inside(rect,x,y); };\n\n        int remWalls=0;\n        for(auto [x,y]: wallCells){\n            if(targetWall[x][y] && !blocked[x][y]) remWalls++;\n        }\n\n        int remDoors=0;\n        for(int i=0;i<(int)bestDoors.size();i++){\n            if(!doorClosed[i] && !blocked[bestDoors[i].x][bestDoors[i].y]) remDoors++;\n        }\n\n        bool allInside = true;\n        for(auto &h: humans){\n            if(!insideNow(h.x,h.y)){ allInside=false; break; }\n        }\n\n        // Passability for movement: just avoid already blocked\n        auto passAll = [&](int x,int y)->bool{\n            return inb(x,y) && !blocked[x][y];\n        };\n        auto passInside = [&](int x,int y)->bool{\n            return inb(x,y) && insideNow(x,y) && !blocked[x][y];\n        };\n\n        // Build goals: inside cells adjacent to remaining target walls\n        vector<pair<int,int>> buildGoals;\n        if(remWalls>0){\n            static bool mark[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark[x][y]=false;\n            for(auto [wx,wy]: wallCells){\n                if(!(targetWall[wx][wy] && !blocked[wx][wy])) continue;\n                for(int d=0; d<4; d++){\n                    int nx=wx+dx4[d], ny=wy+dy4[d];\n                    if(inb(nx,ny) && insideNow(nx,ny) && !blocked[nx][ny]){\n                        if(!mark[nx][ny]){\n                            mark[nx][ny]=true;\n                            buildGoals.push_back({nx,ny});\n                        }\n                    }\n                }\n            }\n        }\n\n        vector<vector<int>> distGather, distBuild, distClose;\n        bfs_dist(distGather, {gatherPoint}, passAll);\n\n        if(!buildGoals.empty()) bfs_dist(distBuild, buildGoals, passInside);\n        else distBuild.assign(H+1, vector<int>(W+1, INF));\n\n        // Door inside-neighbor cells for closing phase\n        vector<pair<int,int>> closeGoals;\n        if(remWalls==0 && remDoors>0 && allInside){\n            static bool mark2[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark2[x][y]=false;\n            for(int i=0;i<(int)bestDoors.size();i++){\n                if(doorClosed[i]) continue;\n                auto &d = bestDoors[i];\n                if(blocked[d.x][d.y]) { doorClosed[i]=true; continue; }\n                if(inb(d.inx,d.iny) && insideNow(d.inx,d.iny) && !blocked[d.inx][d.iny]){\n                    if(!mark2[d.inx][d.iny]){\n                        mark2[d.inx][d.iny]=true;\n                        closeGoals.push_back({d.inx,d.iny});\n                    }\n                }\n            }\n        }\n        if(!closeGoals.empty()) bfs_dist(distClose, closeGoals, passInside);\n        else distClose.assign(H+1, vector<int>(W+1, INF));\n\n        vector<char> act(M,'.');\n\n        // 1) Try to close doors (if fence walls are done and all humans inside)\n        if(remWalls==0 && allInside){\n            // attempt close multiple doors per turn\n            for(int di=0; di<(int)bestDoors.size(); di++){\n                if(doorClosed[di]) continue;\n                auto &d = bestDoors[di];\n                if(blocked[d.x][d.y]) { doorClosed[di]=true; continue; }\n                if(!canBuild(d.x,d.y,petAt,humanAt)) continue;\n\n                // find an unassigned human adjacent to door\n                for(int i=0;i<M;i++){\n                    if(act[i] != '.') continue;\n                    int hx=humans[i].x, hy=humans[i].y;\n                    if(manhattan(hx,hy,d.x,d.y)!=1) continue;\n                    for(int dir=0; dir<4; dir++){\n                        if(hx+dx4[dir]==d.x && hy+dy4[dir]==d.y){\n                            act[i]=BUILD_CH[dir];\n                            break;\n                        }\n                    }\n                    if(act[i] != '.'){\n                        // mark to close in local sim later\n                        break;\n                    }\n                }\n            }\n        }\n\n        // 2) Build any adjacent remaining target wall cell (any human, inside or outside)\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n            for(int dir=0; dir<4; dir++){\n                int tx=hx+dx4[dir], ty=hy+dy4[dir];\n                if(!inb(tx,ty)) continue;\n                if(targetWall[tx][ty] && !blocked[tx][ty]){\n                    if(canBuild(tx,ty,petAt,humanAt)){\n                        act[i]=BUILD_CH[dir];\n                        break;\n                    }\n                }\n            }\n        }\n\n        // 3) Move\n        auto tiePenaltyAll = [&](int x,int y)->int{\n            // discourage stopping on target wall cells that will be built (to reduce blocking builds)\n            if(targetWall[x][y] && !blocked[x][y]) return 10;\n            return 0;\n        };\n        auto tiePenaltyInside = [&](int x,int y)->int{\n            return 0;\n        };\n\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            if(!insideNow(hx,hy)){\n                if(distGather[hx][hy] >= INF){\n                    act[i]='.';\n                }else{\n                    act[i] = step_by_dist(hx,hy,distGather,passAll,tiePenaltyAll);\n                }\n            }else{\n                if(remWalls>0 && distBuild[hx][hy] < INF){\n                    act[i] = step_by_dist(hx,hy,distBuild,passInside,tiePenaltyInside);\n                }else if(remWalls==0 && remDoors>0 && allInside && distClose[hx][hy] < INF){\n                    act[i] = step_by_dist(hx,hy,distClose,passInside,tiePenaltyInside);\n                }else{\n                    act[i]='.';\n                }\n            }\n        }\n\n        string out;\n        out.reserve(M);\n        for(int i=0;i<M;i++) out.push_back(act[i]);\n        cout << out << \"\\n\" << flush;\n\n        // ---- Local simulation update (humans + blocks) ----\n        static bool willBeBlocked[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) willBeBlocked[x][y]=false;\n\n        // Apply builds (successful)\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='u') dir=0;\n            if(c=='d') dir=1;\n            if(c=='l') dir=2;\n            if(c=='r') dir=3;\n            if(dir==-1) continue;\n            int tx=humans[i].x+dx4[dir], ty=humans[i].y+dy4[dir];\n            if(inb(tx,ty) && canBuild(tx,ty,petAt,humanAt)){\n                willBeBlocked[tx][ty]=true;\n            }\n        }\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n            if(willBeBlocked[x][y]) blocked[x][y]=true;\n        }\n\n        // Apply moves\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='U') dir=0;\n            if(c=='D') dir=1;\n            if(c=='L') dir=2;\n            if(c=='R') dir=3;\n            if(dir==-1) continue;\n            int nx=humans[i].x+dx4[dir], ny=humans[i].y+dy4[dir];\n            if(inb(nx,ny) && !blocked[nx][ny] && !willBeBlocked[nx][ny]){\n                humans[i].x=nx; humans[i].y=ny;\n            }\n        }\n\n        // Update doorClosed flags if doors got blocked this turn\n        for(int i=0;i<(int)bestDoors.size();i++){\n            if(doorClosed[i]) continue;\n            auto &d=bestDoors[i];\n            if(blocked[d.x][d.y]) doorClosed[i]=true;\n        }\n\n        // ---- Read pet moves and update pets ----\n        for(int i=0;i<N;i++){\n            string s; cin >> s;\n            if(s==\".\") continue;\n            for(char c: s){\n                int dir=-1;\n                if(c=='U') dir=0;\n                if(c=='D') dir=1;\n                if(c=='L') dir=2;\n                if(c=='R') dir=3;\n                if(dir==-1) continue;\n                int nx=pets[i].x+dx4[dir], ny=pets[i].y+dy4[dir];\n                if(inb(nx,ny) && !blocked[nx][ny]){\n                    pets[i].x=nx; pets[i].y=ny;\n                }\n            }\n        }\n    }\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int V = N * N;\nstatic constexpr int INF = 1e9;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() : st(chrono::high_resolution_clock::now()) {}\n    double elapsed() const {\n        auto ed = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(ed - st).count();\n    }\n};\n\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3; // 'R'\n}\nstatic inline char dirCh(int d) {\n    static const char dc[4] = {'U','D','L','R'};\n    return dc[d];\n}\nstatic inline char oppDir(char c){\n    if(c=='U') return 'D';\n    if(c=='D') return 'U';\n    if(c=='L') return 'R';\n    return 'L';\n}\n\nstruct Evaluator {\n    int s, t;\n    float p, q;\n    const int (*nxt)[4];\n    array<float, V> dist{}, ndist{};\n\n    Evaluator(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p((float)p_), q((float)(1.0 - p_)), nxt(nxt_) {}\n\n    double eval(const string &seq) {\n        dist.fill(0.0f);\n        ndist.fill(0.0f);\n        dist[s] = 1.0f;\n        double E = 0.0;\n        const int L = (int)seq.size();\n        for (int step = 0; step < L; step++) {\n            ndist.fill(0.0f);\n            const int d = dirId(seq[step]);\n            double hit = 0.0;\n\n            for (int pos = 0; pos < V; pos++) {\n                float pr = dist[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    ndist[pos] += pr;\n                } else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    ndist[pos] += st;\n                    if (np == t) hit += (double)mv;\n                    else ndist[np] += mv;\n                }\n            }\n            dist = ndist;\n            E += hit * (401.0 - (step + 1));\n        }\n        return E;\n    }\n};\n\nstruct Meta {\n    int parent;\n    char mv;\n};\n\nstruct Cand {\n    int meta;\n    double exp;      // accumulated expected score so far\n    double key;      // beam sort key\n    float rem;       // remaining probability mass not yet reached\n    float avgd;      // avg dist-to-target under remaining mass (for sorting diversity)\n    array<float, V> prob;\n};\n\nstatic string reconstruct(const vector<Meta>& meta, int node) {\n    string s;\n    while (node != 0) {\n        s.push_back(meta[node].mv);\n        node = meta[node].parent;\n    }\n    reverse(s.begin(), s.end());\n    return s;\n}\n\nstatic string shortest_path_tiled_200(int s, int t, const int nxt[V][4]) {\n    vector<int> prev(V, -1);\n    vector<char> prevC(V, '?');\n    deque<int> dq;\n    dq.push_back(s);\n    prev[s] = s;\n\n    while (!dq.empty()) {\n        int x = dq.front(); dq.pop_front();\n        if (x == t) break;\n        for (int d = 0; d < 4; d++) {\n            int y = nxt[x][d];\n            if (y == x) continue;\n            if (prev[y] != -1) continue;\n            prev[y] = x;\n            prevC[y] = dirCh(d);\n            dq.push_back(y);\n        }\n    }\n    // reconstruct\n    string path;\n    if (prev[t] == -1) {\n        // should not happen (reachable guaranteed). fallback: arbitrary.\n        path = \"D\";\n    } else {\n        int cur = t;\n        while (cur != s) {\n            path.push_back(prevC[cur]);\n            cur = prev[cur];\n        }\n        reverse(path.begin(), path.end());\n    }\n    if (path.empty()) path = \"D\";\n\n    string out;\n    out.reserve(200);\n    while ((int)out.size() < 200) out += path;\n    out.resize(200);\n    return out;\n}\n\nstatic string beam_search_200(\n    int s, int t, double p,\n    const int nxt[V][4],\n    const vector<int>& distToT,\n    Timer &timer,\n    double timeLimitSec\n) {\n    const double q = 1.0 - p;\n    int W = (p >= 0.35 ? 900 : 750); // slightly wider than before\n\n    // Keep some candidates by different criteria to avoid brittle pruning\n    int keepKey = (int)(W * 0.55);\n    int keepExp = (int)(W * 0.25);\n    int keepRem = W - keepKey - keepExp;\n\n    vector<Meta> meta;\n    meta.reserve(300000);\n    meta.push_back({-1, '?'});\n\n    vector<Cand> cur;\n    cur.reserve(W);\n\n    Cand root;\n    root.meta = 0;\n    root.exp = 0.0;\n    root.key = 0.0;\n    root.rem = 1.0f;\n    root.avgd = (float)distToT[s];\n    root.prob.fill(0.0f);\n    root.prob[s] = 1.0f;\n    if (s == t) {\n        root.prob[s] = 0.0f;\n        root.rem = 0.0f;\n        root.avgd = 0.0f;\n    }\n    cur.push_back(root);\n\n    for (int depth = 0; depth < 200; depth++) {\n        if (timer.elapsed() > timeLimitSec) break;\n\n        vector<Cand> all;\n        all.reserve(cur.size() * 4);\n\n        for (const auto &c : cur) {\n            if (c.rem < 1e-12f) continue;\n\n            for (int d = 0; d < 4; d++) {\n                Cand ch;\n                ch.prob.fill(0.0f);\n                double hit = 0.0;\n\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = c.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    int np = nxt[pos][d];\n                    if (np == pos) {\n                        ch.prob[pos] += prf;\n                    } else {\n                        double pr = (double)prf;\n                        double mv = pr * q;\n                        double st = pr * p;\n                        if (np == t) hit += mv;\n                        else ch.prob[np] += (float)mv;\n                        ch.prob[pos] += (float)st;\n                    }\n                }\n\n                int turn = depth + 1;\n                ch.exp = c.exp + hit * (401.0 - turn);\n\n                double rem = 0.0, sumd = 0.0;\n                int mind = INF;\n                for (int pos = 0; pos < V; pos++) {\n                    float prf = ch.prob[pos];\n                    if (prf <= 0.0f) continue;\n                    rem += prf;\n                    int dtt = distToT[pos];\n                    sumd += (double)prf * dtt;\n                    mind = min(mind, dtt);\n                }\n                ch.rem = (float)rem;\n                ch.avgd = (rem > 1e-12 ? (float)(sumd / rem) : 0.0f);\n\n                // Heuristic key: current exp + remaining mass * (optimistic future reward estimate)\n                double key = ch.exp;\n                int remainingSteps = 200 - turn;\n                if (rem > 1e-12 && mind <= remainingSteps) {\n                    double avgd = sumd / max(rem, 1e-12);\n                    // forgetting makes effective progress slower ~1/q\n                    double estTime = (double)turn + avgd / max(1e-6, q);\n                    estTime = min(estTime, 200.0);\n                    double estAdd = rem * max(0.0, 401.0 - estTime);\n                    // also slightly reward having already reached some probability mass\n                    double reached = 1.0 - rem;\n                    key = ch.exp + 0.85 * estAdd + 8.0 * reached;\n                }\n                ch.key = key;\n\n                meta.push_back({c.meta, dirCh(d)});\n                ch.meta = (int)meta.size() - 1;\n\n                all.push_back(std::move(ch));\n            }\n        }\n\n        if (all.empty()) break;\n\n        int M = (int)all.size();\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        vector<char> chosen(M, 0);\n        vector<int> picked;\n        picked.reserve(min(W, M));\n\n        auto pickTop = [&](int need, auto cmp) {\n            if (need <= 0) return;\n            vector<int> id = idx;\n            need = min(need, (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(), cmp);\n            id.resize(need);\n            sort(id.begin(), id.end(), cmp);\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) {\n                    chosen[i] = 1;\n                    picked.push_back(i);\n                }\n            }\n        };\n\n        // By key\n        pickTop(keepKey, [&](int a, int b){ return all[a].key > all[b].key; });\n        // By exp (exact so far)\n        pickTop(keepExp, [&](int a, int b){ return all[a].exp > all[b].exp; });\n        // By remaining mass (smaller rem is better => already reached more)\n        pickTop(keepRem, [&](int a, int b){ return all[a].rem < all[b].rem; });\n\n        // If still not enough (due to duplicates), fill by key\n        if ((int)picked.size() < min(W, M)) {\n            vector<int> id = idx;\n            int need = min(W - (int)picked.size(), (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(),\n                        [&](int a, int b){ return all[a].key > all[b].key; });\n            id.resize(need);\n            sort(id.begin(), id.end(), [&](int a, int b){ return all[a].key > all[b].key; });\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) {\n                    chosen[i] = 1;\n                    picked.push_back(i);\n                }\n            }\n        }\n\n        vector<Cand> nb;\n        nb.reserve(picked.size());\n        for (int i : picked) nb.push_back(std::move(all[i]));\n        cur.swap(nb);\n    }\n\n    // Choose best by exp among current beam\n    int bestMeta = cur[0].meta;\n    double bestExp = cur[0].exp;\n    for (auto &c : cur) {\n        if (c.exp > bestExp) {\n            bestExp = c.exp;\n            bestMeta = c.meta;\n        }\n    }\n\n    string ans = reconstruct(meta, bestMeta);\n    if ((int)ans.size() < 200) ans.append(200 - ans.size(), 'U');\n    if ((int)ans.size() > 200) ans.resize(200);\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TL = 1.97;         // total internal budget\n    const double BEAM_TL = 0.85;    // budget for beam (leave room for SA)\n\n    int si, sj, ti, tj;\n    double p;\n    cin >> si >> sj >> ti >> tj >> p;\n\n    vector<string> h(N);\n    for (int i = 0; i < N; i++) cin >> h[i];\n    vector<string> v(N - 1);\n    for (int i = 0; i < N - 1; i++) cin >> v[i];\n\n    auto id = [&](int r, int c){ return r * N + c; };\n    int s = id(si, sj);\n    int t = id(ti, tj);\n\n    // Precompute transitions with walls.\n    static int nxt[V][4];\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int cur = id(r, c);\n        // U\n        if (r == 0) nxt[cur][0] = cur;\n        else nxt[cur][0] = (v[r-1][c] == '0') ? id(r-1, c) : cur;\n        // D\n        if (r == N-1) nxt[cur][1] = cur;\n        else nxt[cur][1] = (v[r][c] == '0') ? id(r+1, c) : cur;\n        // L\n        if (c == 0) nxt[cur][2] = cur;\n        else nxt[cur][2] = (h[r][c-1] == '0') ? id(r, c-1) : cur;\n        // R\n        if (c == N-1) nxt[cur][3] = cur;\n        else nxt[cur][3] = (h[r][c] == '0') ? id(r, c+1) : cur;\n    }\n\n    // Distances to target (BFS on undirected grid-with-walls graph).\n    vector<int> distToT(V, INF);\n    {\n        deque<int> dq;\n        distToT[t] = 0;\n        dq.push_back(t);\n        while (!dq.empty()) {\n            int x = dq.front(); dq.pop_front();\n            int dx = distToT[x] + 1;\n            for (int d = 0; d < 4; d++) {\n                int y = nxt[x][d];\n                if (y == x) continue;\n                if (distToT[y] > dx) {\n                    distToT[y] = dx;\n                    dq.push_back(y);\n                }\n            }\n        }\n    }\n\n    Evaluator evaluator(s, t, p, nxt);\n\n    // Candidate 1: beam search\n    string ans1 = beam_search_200(s, t, p, nxt, distToT, timer, BEAM_TL);\n    double sc1 = evaluator.eval(ans1);\n\n    // Candidate 2: shortest path repeated to length 200 (diversification)\n    string ans2 = shortest_path_tiled_200(s, t, nxt);\n    double sc2 = evaluator.eval(ans2);\n\n    string best = (sc2 > sc1 ? ans2 : ans1);\n    double bestScore = max(sc1, sc2);\n\n    // Quick greedy single-position improvement (one pass, randomized order)\n    {\n        if (timer.elapsed() < TL * 0.55) {\n            string cur = best;\n            double curScore = bestScore;\n\n            vector<int> order(200);\n            iota(order.begin(), order.end(), 0);\n            std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int idx : order) {\n                if (timer.elapsed() > TL * 0.70) break;\n                char orig = cur[idx];\n                double localBestScore = curScore;\n                char localBestChar = orig;\n                for (int d = 0; d < 4; d++) {\n                    char c = dirCh(d);\n                    if (c == orig) continue;\n                    cur[idx] = c;\n                    double scc = evaluator.eval(cur);\n                    if (scc > localBestScore) {\n                        localBestScore = scc;\n                        localBestChar = c;\n                    }\n                }\n                cur[idx] = localBestChar;\n                curScore = localBestScore;\n            }\n\n            if (curScore > bestScore) {\n                bestScore = curScore;\n                best = cur;\n            }\n        }\n    }\n\n    // Simulated annealing until time limit\n    {\n        std::mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n        auto rnd01 = [&]() -> double {\n            return (double)rng() / (double)rng.max();\n        };\n        auto rndi = [&](int lo, int hi) -> int { // inclusive\n            std::uniform_int_distribution<int> dist(lo, hi);\n            return dist(rng);\n        };\n\n        string cur = best;\n        double curScore = bestScore;\n\n        const double T0 = 2.0;   // on E[S] scale (~0..400)\n        const double T1 = 0.05;\n\n        while (timer.elapsed() < TL) {\n            double tsec = timer.elapsed();\n            double frac = min(1.0, max(0.0, (tsec - 0.70) / max(1e-9, (TL - 0.70))));\n            double temp = T0 * pow(T1 / T0, frac);\n\n            int type = rndi(0, 99);\n            if (type < 60) {\n                // single change\n                int i = rndi(0, 199);\n                char old = cur[i];\n                char nc = dirCh(rndi(0, 3));\n                if (nc == old) continue;\n                cur[i] = nc;\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    cur[i] = old;\n                }\n            } else if (type < 85) {\n                // swap\n                int i = rndi(0, 199), j = rndi(0, 199);\n                if (i == j) continue;\n                swap(cur[i], cur[j]);\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    swap(cur[i], cur[j]);\n                }\n            } else {\n                // randomize short segment\n                int l = rndi(0, 199);\n                int len = rndi(2, 8);\n                int r = min(200, l + len);\n                string old = cur.substr(l, r - l);\n                for (int i = l; i < r; i++) cur[i] = dirCh(rndi(0, 3));\n\n                double ns = evaluator.eval(cur);\n                double delta = ns - curScore;\n                if (delta >= 0 || exp(delta / temp) > rnd01()) {\n                    curScore = ns;\n                    if (ns > bestScore) {\n                        bestScore = ns;\n                        best = cur;\n                    }\n                } else {\n                    for (int i = l; i < r; i++) cur[i] = old[i - l];\n                }\n            }\n        }\n    }\n\n    cout << best << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TILES = N * N;\nstatic constexpr int PORTS = TILES * 4;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU64() % (uint64_t)(hi - lo + 1));\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct EvalResult {\n    long long baseScore;     // L1*L2 (true score if >=2 loops else 0)\n    int L1, L2;\n    int loopCount;\n    int compCount;\n    int matchedEdges;        // active-active borders\n    int openEnds;            // endpoints with deg==1\n    int largestCompLen;      // max(compSize/2) over all components (loops or paths)\n    long long sumCompLenSq;  // sum (compLen^2) over all components\n    double energy;           // SA energy\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Input\n    vector<uint8_t> initState(TILES);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) initState[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    // Rotation map (90deg CCW)\n    // 0->1->2->3->0, 4<->5, 6<->7\n    array<uint8_t, 8> rot1 = {1,2,3,0,5,4,7,6};\n    uint8_t rotStep[8][4];\n    for (int t = 0; t < 8; t++) {\n        rotStep[t][0] = (uint8_t)t;\n        rotStep[t][1] = rot1[t];\n        rotStep[t][2] = rot1[rotStep[t][1]];\n        rotStep[t][3] = rot1[rotStep[t][2]];\n    }\n\n    // side masks (L,U,R,D) bits 0..3, and internal pairings\n    uint8_t sideMask[8];\n    uint8_t pairCnt[8];\n    uint8_t pairs[8][2][2]; // up to 2 segments (each a pair of sides)\n\n    auto set1 = [&](int t, int a, int b, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 1;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = pairs[t][1][1] = 255;\n    };\n    auto set2 = [&](int t, int a, int b, int c, int d, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 2;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = (uint8_t)c;\n        pairs[t][1][1] = (uint8_t)d;\n    };\n\n    // 0: L-U\n    set1(0, 0, 1, (1u<<0) | (1u<<1));\n    // 1: L-D\n    set1(1, 0, 3, (1u<<0) | (1u<<3));\n    // 2: R-D\n    set1(2, 2, 3, (1u<<2) | (1u<<3));\n    // 3: U-R\n    set1(3, 1, 2, (1u<<1) | (1u<<2));\n    // 4: (L-U) and (R-D)\n    set2(4, 0, 1, 2, 3, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 5: (L-D) and (U-R)\n    set2(5, 0, 3, 1, 2, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 6: L-R\n    set1(6, 0, 2, (1u<<0) | (1u<<2));\n    // 7: U-D\n    set1(7, 1, 3, (1u<<1) | (1u<<3));\n\n    auto applyFromInit = [&](int idx, uint8_t r) -> uint8_t {\n        return rotStep[initState[idx]][r & 3];\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift64 rng(seed);\n\n    // Current state\n    vector<uint8_t> curRot(TILES, 0);\n    vector<uint8_t> curState(TILES, 0);\n    vector<uint8_t> curMask(TILES, 0);\n\n    // indices of 4/5 tiles (pairing-changing tiles)\n    vector<int> pairTiles;\n    pairTiles.reserve(TILES);\n    for (int p = 0; p < TILES; p++) {\n        if (initState[p] == 4 || initState[p] == 5) pairTiles.push_back(p);\n    }\n\n    // Random init\n    for (int p = 0; p < TILES; p++) {\n        uint8_t r = (uint8_t)rng.nextInt(0, 3);\n        curRot[p] = r;\n        curState[p] = applyFromInit(p, r);\n        curMask[p] = sideMask[curState[p]];\n    }\n\n    // Greedy init:\n    // - reward active-active matches\n    // - penalize mismatch\n    // - penalize boundary leaks\n    // - add pairing potential for 4/5 tiles (and generally for any tile's internal pairs)\n    auto cont = [&](int p, int side) -> int {\n        int i = p / N, j = p % N;\n        if (side == 0) { // L\n            if (j == 0) return 0;\n            return (curMask[p - 1] & (1u << 2)) ? 1 : 0;\n        } else if (side == 1) { // U\n            if (i == 0) return 0;\n            return (curMask[p - N] & (1u << 3)) ? 1 : 0;\n        } else if (side == 2) { // R\n            if (j == N - 1) return 0;\n            return (curMask[p + 1] & (1u << 0)) ? 1 : 0;\n        } else { // D\n            if (i == N - 1) return 0;\n            return (curMask[p + N] & (1u << 1)) ? 1 : 0;\n        }\n    };\n\n    auto greedyLocalScore = [&](int p, uint8_t stCand) -> int {\n        int i = p / N, j = p % N;\n        uint8_t mCand = sideMask[stCand];\n\n        int sc = 0;\n        // border match score: only active-active is good\n        auto evalSide = [&](int side, int ni, int nj, int oppSide) {\n            bool a = (mCand >> side) & 1;\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (a) sc -= 6; // boundary leak\n                return;\n            }\n            int q = ni * N + nj;\n            bool b = (curMask[q] >> oppSide) & 1;\n            if (a && b) sc += 5;\n            else if (a != b) sc -= 5;\n            // both inactive: 0\n        };\n\n        evalSide(0, i, j - 1, 2);\n        evalSide(1, i - 1, j, 3);\n        evalSide(2, i, j + 1, 0);\n        evalSide(3, i + 1, j, 1);\n\n        // internal pairing potential:\n        // prefer pairing that connects \"continuable\" sides together.\n        int c[4] = { cont(p,0), cont(p,1), cont(p,2), cont(p,3) };\n        int ps = 0;\n        for (int k = 0; k < pairCnt[stCand]; k++) {\n            int a = pairs[stCand][k][0], b = pairs[stCand][k][1];\n            ps += c[a] * c[b];\n        }\n        sc += ps * 3;\n\n        return sc;\n    };\n\n    vector<int> order(TILES);\n    iota(order.begin(), order.end(), 0);\n\n    for (int sweep = 0; sweep < 8; sweep++) {\n        for (int i = TILES - 1; i > 0; i--) {\n            int j = (int)(rng.nextU64() % (uint64_t)(i + 1));\n            swap(order[i], order[j]);\n        }\n        for (int idx = 0; idx < TILES; idx++) {\n            int p = order[idx];\n            int bestSc = INT_MIN;\n            uint8_t bestDelta = 0;\n            uint8_t base = curState[p];\n            for (uint8_t dlt = 0; dlt < 4; dlt++) {\n                uint8_t stCand = rotStep[base][dlt];\n                int sc = greedyLocalScore(p, stCand);\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestDelta = dlt;\n                }\n            }\n            if (bestDelta != 0) {\n                curRot[p] = (uint8_t)((curRot[p] + bestDelta) & 3);\n                curState[p] = rotStep[curState[p]][bestDelta];\n                curMask[p] = sideMask[curState[p]];\n            }\n        }\n    }\n\n    // Evaluation buffers\n    static int degArr[PORTS];\n    static int nb1[PORTS];\n    static int nb2[PORTS];\n    static uint8_t vis[PORTS];\n    static int stackBuf[PORTS];\n\n    auto addEdge = [&](int u, int v) {\n        int du = degArr[u]++;\n        if (du == 0) nb1[u] = v;\n        else nb2[u] = v;\n\n        int dv = degArr[v]++;\n        if (dv == 0) nb1[v] = u;\n        else nb2[v] = u;\n    };\n\n    auto evaluate = [&]() -> EvalResult {\n        memset(degArr, 0, sizeof(degArr));\n        memset(nb1, 0xFF, sizeof(nb1)); // -1\n        memset(nb2, 0xFF, sizeof(nb2));\n        memset(vis, 0, sizeof(vis));\n\n        // internal edges\n        for (int p = 0; p < TILES; p++) {\n            int base = p * 4;\n            uint8_t st = curState[p];\n            for (int k = 0; k < pairCnt[st]; k++) {\n                int a = pairs[st][k][0];\n                int b = pairs[st][k][1];\n                addEdge(base + a, base + b);\n            }\n        }\n\n        // external edges\n        int matchedEdges = 0;\n        // horizontal\n        for (int i = 0; i < N; i++) {\n            int row = i * N;\n            for (int j = 0; j < N - 1; j++) {\n                int p = row + j;\n                int q = p + 1;\n                if ((curMask[p] & (1u << 2)) && (curMask[q] & (1u << 0))) {\n                    addEdge(p * 4 + 2, q * 4 + 0);\n                    matchedEdges++;\n                }\n            }\n        }\n        // vertical\n        for (int i = 0; i < N - 1; i++) {\n            int row = i * N;\n            int row2 = (i + 1) * N;\n            for (int j = 0; j < N; j++) {\n                int p = row + j;\n                int q = row2 + j;\n                if ((curMask[p] & (1u << 3)) && (curMask[q] & (1u << 1))) {\n                    addEdge(p * 4 + 3, q * 4 + 1);\n                    matchedEdges++;\n                }\n            }\n        }\n\n        int openEnds = 0;\n        for (int u = 0; u < PORTS; u++) if (degArr[u] == 1) openEnds++;\n\n        int L1 = 0, L2 = 0;\n        int loopCount = 0;\n        int compCount = 0;\n        int largestCompLen = 0;\n        long long sumCompLenSq = 0;\n\n        for (int s = 0; s < PORTS; s++) {\n            if (degArr[s] == 0 || vis[s]) continue;\n            compCount++;\n\n            int top = 0;\n            stackBuf[top++] = s;\n            vis[s] = 1;\n\n            int compSize = 0;\n            bool isCycle = true;\n\n            while (top) {\n                int x = stackBuf[--top];\n                compSize++;\n                if (degArr[x] != 2) isCycle = false;\n\n                int a = nb1[x], b = nb2[x];\n                if (a != -1 && !vis[a]) { vis[a] = 1; stackBuf[top++] = a; }\n                if (b != -1 && !vis[b]) { vis[b] = 1; stackBuf[top++] = b; }\n            }\n\n            int compLen = compSize / 2; // moves\n            largestCompLen = max(largestCompLen, compLen);\n            sumCompLenSq += 1LL * compLen * compLen;\n\n            if (isCycle) {\n                loopCount++;\n                if (compLen > L1) { L2 = L1; L1 = compLen; }\n                else if (compLen > L2) { L2 = compLen; }\n            }\n        }\n\n        long long base = (loopCount >= 2) ? 1LL * L1 * L2 : 0LL;\n\n        // Energy:\n        // - if >=2 loops exist: focus on product, but discourage too many loops\n        // - if <2: grow large components (easy to close later) and reduce fragmentation\n        double energy;\n        if (loopCount >= 2) {\n            energy = base * 200.0\n                   + (L1 + L2) * 50.0\n                   + largestCompLen * 5.0\n                   + sumCompLenSq * 0.002\n                   - openEnds * 2.0\n                   - max(0, loopCount - 2) * 500.0;\n        } else if (loopCount == 1) {\n            energy = L1 * 60.0\n                   + largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 6000.0;\n        } else {\n            energy = largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 12000.0;\n        }\n\n        return EvalResult{base, L1, L2, loopCount, compCount, matchedEdges, openEnds,\n                          largestCompLen, sumCompLenSq, energy};\n    };\n\n    EvalResult curEval = evaluate();\n    long long bestBase = curEval.baseScore;\n    int bestTie = curEval.L1 + curEval.L2;\n    vector<uint8_t> bestRot = curRot;\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.93;\n\n    // SA temperature (energy scale is now larger)\n    const double T0 = 12000.0;\n    const double T1 = 150.0;\n\n    struct Backup {\n        int p;\n        uint8_t rot, st, mask;\n    };\n\n    auto applyDelta = [&](int p, uint8_t delta) {\n        if ((delta & 3) == 0) return;\n        curRot[p] = (uint8_t)((curRot[p] + delta) & 3);\n        curState[p] = rotStep[curState[p]][delta & 3];\n        curMask[p] = sideMask[curState[p]];\n    };\n\n    long long iter = 0;\n    while (true) {\n        iter++;\n        if ((iter & 1023) == 0) {\n            double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (sec >= TL) break;\n        }\n\n        // move type\n        int r = (int)(rng.nextU64() % 1000);\n\n        vector<int> ps;\n        vector<uint8_t> deltas;\n\n        if (r < 850) {\n            // single tile (bias to 4/5 tiles sometimes)\n            int p;\n            if (!pairTiles.empty() && rng.nextDouble() < 0.45) {\n                p = pairTiles[rng.nextInt(0, (int)pairTiles.size() - 1)];\n            } else {\n                p = (int)(rng.nextU64() % TILES);\n            }\n            uint8_t delta = (uint8_t)(1 + (rng.nextU32() % 3));\n            uint8_t newS = rotStep[curState[p]][delta];\n            if (newS == curState[p]) { delta = 1; }\n            ps = {p};\n            deltas = {delta};\n        } else if (r < 950) {\n            // 2x2 move\n            int i = rng.nextInt(0, N - 2);\n            int j = rng.nextInt(0, N - 2);\n            int p0 = i * N + j;\n            ps = {p0, p0 + 1, p0 + N, p0 + N + 1};\n            deltas.resize(4);\n            int nonzero = 0;\n            for (int k = 0; k < 4; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,3)] = 1;\n        } else {\n            // 1x3 or 3x1 move\n            bool horiz = (rng.nextU32() & 1);\n            if (horiz) {\n                int i = rng.nextInt(0, N - 1);\n                int j = rng.nextInt(0, N - 3);\n                int p0 = i * N + j;\n                ps = {p0, p0 + 1, p0 + 2};\n            } else {\n                int i = rng.nextInt(0, N - 3);\n                int j = rng.nextInt(0, N - 1);\n                int p0 = i * N + j;\n                ps = {p0, p0 + N, p0 + 2 * N};\n            }\n            deltas.resize(3);\n            int nonzero = 0;\n            for (int k = 0; k < 3; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,2)] = 1;\n        }\n\n        // backup and apply\n        vector<Backup> backups;\n        backups.reserve(ps.size());\n        for (int idx = 0; idx < (int)ps.size(); idx++) {\n            int p = ps[idx];\n            backups.push_back(Backup{p, curRot[p], curState[p], curMask[p]});\n            applyDelta(p, deltas[idx]);\n        }\n\n        EvalResult nxtEval = evaluate();\n\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = min(1.0, sec / TL);\n        double Temp = T0 * pow(T1 / T0, t);\n\n        double diff = nxtEval.energy - curEval.energy;\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else {\n            double prob = exp(diff / Temp);\n            accept = (rng.nextDouble() < prob);\n        }\n\n        if (accept) {\n            curEval = nxtEval;\n            // best by true score, tie by L1+L2\n            int tie = nxtEval.L1 + nxtEval.L2;\n            if (nxtEval.baseScore > bestBase || (nxtEval.baseScore == bestBase && tie > bestTie)) {\n                bestBase = nxtEval.baseScore;\n                bestTie = tie;\n                bestRot = curRot;\n            }\n        } else {\n            // revert\n            for (auto &b : backups) {\n                curRot[b.p] = b.rot;\n                curState[b.p] = b.st;\n                curMask[b.p] = b.mask;\n            }\n        }\n    }\n\n    // output best\n    string out;\n    out.reserve(TILES);\n    for (int p = 0; p < TILES; p++) out.push_back(char('0' + (bestRot[p] & 3)));\n    cout << out << \"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline int hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int bestAlmost = 0;\n    int edgesTotal = 0;\n    int cycleSurplus = 0;\n    int cyclicLargest = 0;\n    int borderOut = 0;\n    int mismatch = 0;\n    int treeMass = 0; // sum of squares of tree component sizes\n    long long obj = 0;\n};\n\nstruct UF {\n    int n;\n    int p[110], sz[110];\n    void init(int n_) {\n        n = n_;\n        for (int i = 0; i < n; i++) { p[i] = i; sz[i] = 1; }\n    }\n    int find(int a) {\n        while (p[a] != a) {\n            p[a] = p[p[a]];\n            a = p[a];\n        }\n        return a;\n    }\n    void unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return;\n        if (sz[a] < sz[b]) swap(a,b);\n        p[b] = a;\n        sz[a] += sz[b];\n    }\n};\n\nstruct Solver {\n    int N, T;\n    int NN;\n    int V; // N*N - 1\n    vector<uint8_t> init;\n    int initBlank = -1;\n\n    // blank move directions: U D L R\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char dch[4] = {'U','D','L','R'};\n    const int opp[4] = {1,0,3,2};\n\n    // precomputed legal moves from each blank cell\n    int moveCnt[110];\n    int moveList[110][4];\n\n    // edge storage for evaluation (max 2*N*(N-1) <= 180 for N=10)\n    int eU[256], eV[256];\n\n    void precompute_moves() {\n        for (int pos = 0; pos < NN; pos++) {\n            int r = pos / N, c = pos % N;\n            int k = 0;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    moveList[pos][k++] = d;\n                }\n            }\n            moveCnt[pos] = k;\n        }\n    }\n\n    inline void do_move_inplace(vector<uint8_t>& b, int& blank, int d) const {\n        int r = blank / N, c = blank % N;\n        int nb = (r + dr[d]) * N + (c + dc[d]);\n        swap(b[blank], b[nb]);\n        blank = nb;\n    }\n\n    Metrics evaluate(const vector<uint8_t>& b) {\n        UF uf;\n        uf.init(NN);\n\n        int eidx = 0;\n        int edgesTotal = 0;\n        int borderOut = 0;\n        int mismatch = 0;\n\n        // border penalties + adjacency processing (also union matches)\n        for (int r = 0; r < N; r++) {\n            int base = r * N;\n            for (int c = 0; c < N; c++) {\n                int id = base + c;\n                uint8_t t = b[id];\n                if (t == 0) continue;\n\n                if (r == 0 && (t & 2)) borderOut++;\n                if (r == N-1 && (t & 8)) borderOut++;\n                if (c == 0 && (t & 1)) borderOut++;\n                if (c == N-1 && (t & 4)) borderOut++;\n\n                // right neighbor\n                if (c + 1 < N) {\n                    int id2 = id + 1;\n                    uint8_t t2 = b[id2];\n                    bool ar = (t & 4);\n                    bool bl = (t2 & 1);\n                    // mismatch counts line-ends that do not match\n                    if (t != 0 && ar && !(t2 != 0 && bl)) mismatch++;\n                    if (t2 != 0 && bl && !(t != 0 && ar)) mismatch++;\n                    if (t2 != 0 && ar && bl) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n                // down neighbor\n                if (r + 1 < N) {\n                    int id2 = id + N;\n                    uint8_t t2 = b[id2];\n                    bool ad = (t & 8);\n                    bool bu = (t2 & 2);\n                    if (t != 0 && ad && !(t2 != 0 && bu)) mismatch++;\n                    if (t2 != 0 && bu && !(t != 0 && ad)) mismatch++;\n                    if (t2 != 0 && ad && bu) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n            }\n        }\n\n        static int vcnt[110];\n        static int ecnt[110];\n        for (int i = 0; i < NN; i++) { vcnt[i] = 0; ecnt[i] = 0; }\n\n        for (int i = 0; i < NN; i++) {\n            if (b[i] == 0) continue;\n            vcnt[uf.find(i)]++;\n        }\n        for (int k = 0; k < eidx; k++) {\n            int root = uf.find(eU[k]);\n            ecnt[root]++;\n        }\n\n        Metrics m;\n        m.edgesTotal = edgesTotal;\n        m.borderOut = borderOut;\n        m.mismatch = mismatch;\n\n        int largestTree = 0;\n        int bestAlmost = 0;\n        int cycleSurplus = 0;\n        int cyclicLargest = 0;\n        long long treeMass = 0;\n\n        for (int i = 0; i < NN; i++) {\n            int Vc = vcnt[i];\n            if (Vc == 0) continue;\n            int Ec = ecnt[i];\n            int extra = max(0, Ec - (Vc - 1));\n            cycleSurplus += extra;\n            if (extra > 0) cyclicLargest = max(cyclicLargest, Vc);\n\n            if (extra == 0) {\n                largestTree = max(largestTree, Vc);\n                treeMass += 1LL * Vc * Vc;\n            }\n            // closeness-to-tree potential (penalize extra edges strongly)\n            bestAlmost = max(bestAlmost, Vc - 10 * extra);\n        }\n\n        m.largestTree = largestTree;\n        m.bestAlmost = bestAlmost;\n        m.cycleSurplus = cycleSurplus;\n        m.cyclicLargest = cyclicLargest;\n        m.treeMass = (int)min<long long>(treeMass, INT_MAX);\n\n        // Objective: prioritize real largest-tree size, then push away from cycles,\n        // and encourage border/port consistency.\n        long long obj = 0;\n        obj += 1000000000LL * m.largestTree;          // primary\n        obj += 20000000LL   * m.bestAlmost;           // secondary\n        obj += 5000LL       * m.treeMass;             // encourage big forests\n        obj += 200000LL     * m.edgesTotal;           // matched edges help (but not at all costs)\n        obj -= 50000000LL   * m.cyclicLargest;        // big cyclic component is disastrous\n        obj -= 20000000LL   * m.cycleSurplus;         // cycles are bad\n        obj -= 500000LL     * m.borderOut;            // outward ports cannot be matched\n        obj -= 20000LL      * m.mismatch;             // unmatched ends hurt\n\n        m.obj = obj;\n        return m;\n    }\n\n    struct RunResult {\n        string path;\n        int bestS;\n        int bestLen;\n    };\n\n    RunResult run_once(XorShift64& rng, double time_frac) {\n        vector<uint8_t> b = init;\n        int blank = initBlank;\n\n        Metrics cur = evaluate(b);\n        int bestS = cur.largestTree;\n        int bestLen = 0;\n        string path;\n        path.reserve(T);\n\n        int prevd = -1;\n\n        // exploration schedule (vary per run)\n        double eps0 = 0.40 - 0.15 * time_frac; // earlier runs explore more\n        double eps1 = 0.05;\n        // randomize slightly per run\n        eps0 *= (0.85 + 0.30 * rng.next_double());\n        eps1 *= (0.85 + 0.30 * rng.next_double());\n        eps0 = min(0.65, max(0.05, eps0));\n        eps1 = min(0.20, max(0.01, eps1));\n\n        for (int step = 0; step < T; step++) {\n            // build candidate moves from precomputed list\n            int cand[4], cc = 0;\n            int mc = moveCnt[blank];\n            for (int i = 0; i < mc; i++) cand[cc++] = moveList[blank][i];\n\n            // avoid immediate reverse most of the time (but not always)\n            if (prevd != -1 && cc >= 2 && rng.next_double() < 0.90) {\n                int rev = opp[prevd];\n                int nc = 0;\n                for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                if (nc >= 1) cc = nc;\n            }\n\n            struct CandInfo { int d; Metrics m1; long long score; };\n            CandInfo infos[4];\n\n            // evaluate each candidate (1-step)\n            for (int i = 0; i < cc; i++) {\n                int d = cand[i];\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d);\n                Metrics m1 = evaluate(b);\n                // revert\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                infos[i] = {d, m1, m1.obj};\n            }\n\n            // take top-2 by score and do 2-step lookahead on them\n            int order[4];\n            iota(order, order + cc, 0);\n            sort(order, order + cc, [&](int a, int b) {\n                return infos[a].score > infos[b].score;\n            });\n\n            int topk = min(2, cc);\n            for (int t = 0; t < topk; t++) {\n                int idx = order[t];\n                int d1 = infos[idx].d;\n\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d1);\n\n                // enumerate next moves excluding immediate reverse of d1\n                long long best2 = LLONG_MIN;\n                int mc2 = moveCnt[blank];\n                for (int j = 0; j < mc2; j++) {\n                    int d2 = moveList[blank][j];\n                    if (d2 == opp[d1] && mc2 >= 2) continue;\n                    int savedBlank2 = blank;\n                    do_move_inplace(b, blank, d2);\n                    Metrics m2 = evaluate(b);\n                    best2 = max(best2, m2.obj);\n                    // revert\n                    swap(b[savedBlank2], b[blank]);\n                    blank = savedBlank2;\n                }\n\n                // revert state1\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                if (best2 != LLONG_MIN) {\n                    // small influence of lookahead\n                    infos[idx].score = infos[idx].m1.obj + best2 / 10;\n                }\n            }\n\n            // epsilon-greedy choice\n            double eps = eps0 + (eps1 - eps0) * (double)step / max(1, T - 1);\n            int chosen = 0;\n            if (rng.next_double() < eps) {\n                chosen = rng.next_int(0, cc - 1);\n            } else {\n                long long bestScore = LLONG_MIN;\n                for (int i = 0; i < cc; i++) {\n                    // small random tie-break\n                    long long s = infos[i].score + (long long)(rng.next_u64() & 1023ULL);\n                    if (s > bestScore) {\n                        bestScore = s;\n                        chosen = i;\n                    }\n                }\n            }\n\n            int d = infos[chosen].d;\n            do_move_inplace(b, blank, d);\n            path.push_back(dch[d]);\n            prevd = d;\n            cur = infos[chosen].m1;\n\n            int S = cur.largestTree;\n            int len = step + 1;\n            if (S > bestS) {\n                bestS = S;\n                bestLen = len;\n            } else if (S == bestS) {\n                // if perfect, prefer shorter; otherwise shorter is fine too\n                if (len < bestLen) bestLen = len;\n            }\n\n            if (bestS == V) {\n                // first time reaching perfect is already shortest in this run\n                bestLen = len;\n                break;\n            }\n        }\n\n        RunResult rr;\n        rr.bestS = bestS;\n        rr.bestLen = bestLen;\n        rr.path = path.substr(0, bestLen);\n        return rr;\n    }\n\n    string solve() {\n        NN = N * N;\n        V = NN - 1;\n        precompute_moves();\n\n        Metrics m0 = evaluate(init);\n        int globalBestS = m0.largestTree;\n        int globalBestLen = 0;\n        string globalBest = \"\";\n\n        auto st = chrono::high_resolution_clock::now();\n        const double TL = 2.85;\n\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        while (true) {\n            auto now = chrono::high_resolution_clock::now();\n            double elapsed = chrono::duration<double>(now - st).count();\n            if (elapsed >= TL) break;\n\n            double frac = elapsed / TL;\n            RunResult rr = run_once(rng, frac);\n\n            if (rr.bestS > globalBestS) {\n                globalBestS = rr.bestS;\n                globalBestLen = rr.bestLen;\n                globalBest = rr.path;\n            } else if (rr.bestS == globalBestS) {\n                // if perfect, shorter is strictly better; otherwise doesn't affect score, but keep shorter\n                if (rr.bestLen < globalBestLen) {\n                    globalBestLen = rr.bestLen;\n                    globalBest = rr.path;\n                }\n            }\n\n            if (globalBestS == V && globalBestLen == 0) break;\n        }\n\n        if ((int)globalBest.size() > T) globalBest.resize(T);\n        return globalBest;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.T;\n    int N = solver.N;\n\n    solver.init.assign(N * N, 0);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) {\n            int v = hexval(s[j]);\n            solver.init[i * N + j] = (uint8_t)v;\n            if (v == 0) solver.initBlank = i * N + j;\n        }\n    }\n\n    string ans = solver.solve();\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int R = 10000;\nstatic constexpr long long LEN = 100000000LL; // 1e8\nstatic constexpr double U_INACTIVE = R + 4000.0; // |u| > R => line doesn't intersect cake\n\n// ---------------- RNG ----------------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline double uniform01() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double uniform(double lo, double hi) { return lo + (hi - lo) * uniform01(); }\n    inline int uniformInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// ---------------- Geometry / signature ----------------\nstruct Point { int x, y; };\n\nstruct Line {\n    double theta; // [0, pi)\n    double u;     // signed distance along normal\n    long long px, py, qx, qy; // endpoints\n};\n\nstruct Key {\n    uint64_t lo = 0, hi = 0; // for up to 128 lines\n    bool operator==(Key const& o) const noexcept { return lo == o.lo && hi == o.hi; }\n};\n\nstruct KeyHash {\n    size_t operator()(Key const& k) const noexcept {\n        uint64_t h = k.lo ^ splitmix64(k.hi + 0x9e3779b97f4a7c15ULL);\n        return (size_t)splitmix64(h);\n    }\n};\n\nstatic inline int getBit(const Key& k, int idx) {\n    if (idx < 64) return (int)((k.lo >> idx) & 1ULL);\n    return (int)((k.hi >> (idx - 64)) & 1ULL);\n}\nstatic inline void setBit(Key& k, int idx) {\n    if (idx < 64) k.lo |= (1ULL << idx);\n    else k.hi |= (1ULL << (idx - 64));\n}\nstatic inline void toggleBit(Key& k, int idx) {\n    if (idx < 64) k.lo ^= (1ULL << idx);\n    else k.hi ^= (1ULL << (idx - 64));\n}\n\nstatic inline double wrapTheta(double th) {\n    const double PI = acos(-1.0);\n    while (th < 0) th += PI;\n    while (th >= PI) th -= PI;\n    return th;\n}\n\nstatic inline Line buildLine(double theta, double u) {\n    double cs = cos(theta), sn = sin(theta);\n    double tx = -sn, ty = cs;\n    double cx = u * cs, cy = u * sn;\n\n    long double px = (long double)cx + (long double)LEN * (long double)tx;\n    long double py = (long double)cy + (long double)LEN * (long double)ty;\n    long double qx = (long double)cx - (long double)LEN * (long double)tx;\n    long double qy = (long double)cy - (long double)LEN * (long double)ty;\n\n    Line L;\n    L.theta = theta;\n    L.u = u;\n    L.px = llround(px);\n    L.py = llround(py);\n    L.qx = llround(qx);\n    L.qy = llround(qy);\n    if (L.px == L.qx && L.py == L.qy) L.qx += 1;\n    return L;\n}\n\n// exact side test by integer cross product\n// 1 if cross>0, 0 if cross<0, -1 if cross==0 (strawberry disappears) -> reject\nstatic inline int sideBit(const Line& L, const Point& p) {\n    __int128 dx = (__int128)L.qx - (__int128)L.px;\n    __int128 dy = (__int128)L.qy - (__int128)L.py;\n    __int128 ax = (__int128)p.x - (__int128)L.px;\n    __int128 ay = (__int128)p.y - (__int128)L.py;\n    __int128 cr = dx * ay - dy * ax;\n    if (cr > 0) return 1;\n    if (cr < 0) return 0;\n    return -1;\n}\n\nstatic inline bool isInactive(const Line& L) { return fabs(L.u) > (double)R + 1.0; }\n\n// ---------------- State ----------------\nstruct State {\n    int N = 0;\n    int L = 0;\n    vector<Point> pts;\n    vector<Line> lines;\n    vector<Key> sig;\n    boost::unordered_flat_map<Key, int, KeyHash> mp;\n\n    array<int, 11> a{};\n    array<int, 11> b{}; // pieces with exactly d (1..10)\n    long long excess = 0;   // sum max(0,c-10)\n    long long excess2 = 0;  // sum (max(0,c-10))^2\n    int goodPieces = 0;     // regions with 1..10\n\n    void clearCounts() {\n        mp.clear();\n        b.fill(0);\n        excess = excess2 = 0;\n        goodPieces = 0;\n    }\n\n    static inline long long ex(int c) { return (c <= 10) ? 0LL : (long long)(c - 10); }\n    static inline long long ex2(int c) {\n        if (c <= 10) return 0LL;\n        long long e = (long long)(c - 10);\n        return e * e;\n    }\n\n    inline void updateMetrics(int oldC, int newC) {\n        if (1 <= oldC && oldC <= 10) { b[oldC]--; goodPieces--; }\n        if (1 <= newC && newC <= 10) { b[newC]++; goodPieces++; }\n        excess -= ex(oldC);  excess += ex(newC);\n        excess2 -= ex2(oldC); excess2 += ex2(newC);\n    }\n\n    inline void incRegion(const Key& k) {\n        auto it = mp.find(k);\n        if (it == mp.end()) {\n            updateMetrics(0, 1);\n            mp.emplace(k, 1);\n        } else {\n            int oldC = it->second, newC = oldC + 1;\n            updateMetrics(oldC, newC);\n            it->second = newC;\n        }\n    }\n    inline void decRegion(const Key& k) {\n        auto it = mp.find(k);\n        int oldC = it->second, newC = oldC - 1;\n        updateMetrics(oldC, newC);\n        if (newC == 0) mp.erase(it);\n        else it->second = newC;\n    }\n\n    inline int distributed() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], b[d]);\n        return s;\n    }\n\n    inline long long deficit2() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - b[d]);\n            s += 1LL * def * def;\n        }\n        return s;\n    }\n\n    inline long long overWeighted() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int over = max(0, b[d] - a[d]);\n            // overproducing small sizes is more harmful (often indicates oversplitting)\n            s += 1LL * over * (12 - d) * (12 - d);\n        }\n        return s;\n    }\n\n    inline long long secondaryScore() const {\n        // secondary guidance only (no distributed term)\n        long long def2 = deficit2();\n        long long ovW = overWeighted();\n        long long S = 0;\n        S += 1LL * goodPieces * 80;\n        S -= 1LL * excess2 * 3;\n        S -= 1LL * excess * 160;\n        S -= 1LL * def2 * 750;\n        S -= 1LL * ovW * 110;\n        return S;\n    }\n\n    bool buildInitialSignatures() {\n        sig.assign(N, Key{0, 0});\n        clearCounts();\n        mp.reserve((size_t)N * 2 + 64);\n\n        for (int i = 0; i < L; i++) {\n            for (int j = 0; j < N; j++) {\n                int sb = sideBit(lines[i], pts[j]);\n                if (sb == -1) return false;\n                if (sb == 1) setBit(sig[j], i);\n            }\n        }\n        for (int j = 0; j < N; j++) incRegion(sig[j]);\n        return true;\n    }\n\n    // replace one line; update all affected points; rollback on invalid\n    bool applyReplaceLine(int idx, const Line& newLine,\n                          vector<int>& changedIdx, vector<Key>& oldSig) {\n        changedIdx.clear();\n        oldSig.clear();\n        changedIdx.reserve(256);\n        oldSig.reserve(256);\n\n        for (int j = 0; j < N; j++) {\n            int nb = sideBit(newLine, pts[j]);\n            if (nb == -1) {\n                for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n                    int pj = changedIdx[t];\n                    Key os = oldSig[t];\n                    Key cs = sig[pj];\n                    decRegion(cs);\n                    incRegion(os);\n                    sig[pj] = os;\n                }\n                changedIdx.clear();\n                oldSig.clear();\n                return false;\n            }\n            int ob = getBit(sig[j], idx);\n            if (nb == ob) continue;\n\n            changedIdx.push_back(j);\n            oldSig.push_back(sig[j]);\n\n            Key ns = sig[j];\n            toggleBit(ns, idx);\n            decRegion(sig[j]);\n            incRegion(ns);\n            sig[j] = ns;\n        }\n        return true;\n    }\n\n    void rollbackReplaceLine(const vector<int>& changedIdx, const vector<Key>& oldSig) {\n        for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n            int j = changedIdx[t];\n            Key os = oldSig[t];\n            Key cs = sig[j];\n            decRegion(cs);\n            incRegion(os);\n            sig[j] = os;\n        }\n    }\n};\n\n// ---------------- Timer ----------------\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// ---------------- Helper construction ----------------\nstatic Line inactiveLine(RNG& rng, double theta) {\n    double sgn = (rng.uniform01() < 0.5) ? 1.0 : -1.0;\n    return buildLine(theta, sgn * U_INACTIVE);\n}\n\nstatic Line randomActiveLineAnchored(RNG& rng, const vector<Point>& pts, double theta = -1.0, double noiseU = 1100.0) {\n    const double PI = acos(-1.0);\n    if (theta < 0) theta = rng.uniform(0.0, PI);\n    double cs = cos(theta), sn = sin(theta);\n    const Point& p = pts[rng.uniformInt(0, (int)pts.size() - 1)];\n    double proj = cs * (double)p.x + sn * (double)p.y;\n    double u = proj + rng.uniform(-noiseU, noiseU);\n    double lim = R * 0.98;\n    u = max(-lim, min(lim, u));\n    return buildLine(theta, u);\n}\n\nstatic int nearestLineIndex(const vector<Line>& lines, const Point& p) {\n    int best = 0;\n    double bestAbs = 1e100;\n    for (int i = 0; i < (int)lines.size(); i++) {\n        double cs = cos(lines[i].theta), sn = sin(lines[i].theta);\n        double dist = cs * (double)p.x + sn * (double)p.y - lines[i].u;\n        double ad = fabs(dist);\n        if (ad < bestAbs) { bestAbs = ad; best = i; }\n    }\n    return best;\n}\n\nstatic int pickInactiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (isInactive(lines[i])) return i;\n    }\n    // fallback\n    for (int i = 0; i < L; i++) if (isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\nstatic int pickActiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (!isInactive(lines[i])) return i;\n    }\n    for (int i = 0; i < L; i++) if (!isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\n// Greedy deactivation sweep (fast merge repair)\nstatic vector<Line> deactivateSweep(const vector<Line>& inputLines,\n                                   const vector<Point>& pts,\n                                   const array<int,11>& a,\n                                   RNG& rng,\n                                   double timeBudgetSec) {\n    const int L = (int)inputLines.size();\n    State st;\n    st.N = (int)pts.size();\n    st.L = L;\n    st.pts = pts;\n    st.a = a;\n    st.lines = inputLines;\n    if (!st.buildInitialSignatures()) return inputLines;\n\n    int curD = st.distributed();\n    long long curS = st.secondaryScore();\n\n    vector<int> order(L);\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.nextU32()));\n\n    vector<int> changed;\n    vector<Key> oldSig;\n\n    auto t0 = chrono::steady_clock::now();\n    for (int it = 0; it < L; it++) {\n        double el = chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n        if (el > timeBudgetSec) break;\n\n        int i = order[it];\n        if (isInactive(st.lines[i])) continue;\n\n        Line cand = inactiveLine(rng, st.lines[i].theta);\n        int oldD = curD;\n        long long oldS = curS;\n\n        if (!st.applyReplaceLine(i, cand, changed, oldSig)) continue;\n        int newD = st.distributed();\n        long long newS = st.secondaryScore();\n\n        bool accept = (newD > oldD) || (newD == oldD && newS > oldS);\n        if (accept) {\n            st.lines[i] = cand;\n            curD = newD;\n            curS = newS;\n        } else {\n            st.rollbackReplaceLine(changed, oldSig);\n        }\n    }\n    return st.lines;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n    array<int, 11> a{};\n    for (int d = 1; d <= 10; d++) cin >> a[d];\n    vector<Point> pts(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    int totalAtt = 0;\n    for (int d = 1; d <= 10; d++) totalAtt += a[d];\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 2.93;\n    const int L = 100;\n    const int RESTARTS = 4;\n\n    int globalBestD = -1;\n    long long globalBestS = LLONG_MIN;\n    vector<Line> globalBestLines;\n\n    const double PI = acos(-1.0);\n\n    for (int rs = 0; rs < RESTARTS; rs++) {\n        double now = timer.elapsedSec();\n        if (now >= TIME_LIMIT) break;\n        double rem = TIME_LIMIT - now;\n        double budget = rem / (double)(RESTARTS - rs);\n\n        State st;\n        st.N = N;\n        st.L = L;\n        st.pts = pts;\n        st.a = a;\n        st.lines.resize(L);\n\n        // Init: moderate number of active lines; rest inactive.\n        // (Starting too split can make it hard to recover large sizes.)\n        int initActive = 55 + (rs * 8); // diverse restarts\n        initActive = min(90, max(35, initActive));\n\n        for (int i = 0; i < L; i++) {\n            double thetaBase = PI * (i + 0.5) / (double)L;\n            double theta = wrapTheta(thetaBase + rng.uniform(-0.03, 0.03));\n            if (i < initActive) st.lines[i] = randomActiveLineAnchored(rng, pts, theta, 1300.0);\n            else st.lines[i] = inactiveLine(rng, theta);\n        }\n\n        if (!st.buildInitialSignatures()) continue;\n\n        int curD = st.distributed();\n        long long curS = st.secondaryScore();\n\n        int bestD = curD;\n        long long bestS = curS;\n        vector<Line> bestLines = st.lines;\n\n        vector<int> changedIdx;\n        vector<Key> oldSig;\n\n        auto start = chrono::steady_clock::now();\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed >= budget) break;\n            double prog = elapsed / budget;\n\n            // Two-temperature acceptance:\n            // - Td controls willingness to temporarily decrease distributed pieces\n            // - Ts controls secondary-score acceptance when D is unchanged\n            double Td0 = 2.5, Td1 = 0.15;\n            double Ts0 = 250000.0, Ts1 = 12000.0;\n            double Td = Td0 * (1.0 - prog) + Td1 * prog;\n            double Ts = Ts0 * (1.0 - prog) + Ts1 * prog;\n\n            // compute demand bias quickly\n            int defSmall = 0, defLarge = 0;\n            for (int d = 1; d <= 4; d++) defSmall += max(0, st.a[d] - st.b[d]);\n            for (int d = 8; d <= 10; d++) defLarge += max(0, st.a[d] - st.b[d]);\n\n            // focus: find a large region key\n            int focusJ = rng.uniformInt(0, N - 1);\n            int focusCnt = 0;\n            Key focusKey;\n\n            if (rng.uniform01() < 0.55) {\n                int bestJ = focusJ, bestCnt = 0;\n                for (int t = 0; t < 20; t++) {\n                    int j = rng.uniformInt(0, N - 1);\n                    auto it = st.mp.find(st.sig[j]);\n                    int c = (it == st.mp.end()) ? 0 : it->second;\n                    if (c > bestCnt) { bestCnt = c; bestJ = j; }\n                }\n                focusJ = bestJ;\n            }\n            focusKey = st.sig[focusJ];\n            {\n                auto it = st.mp.find(focusKey);\n                focusCnt = (it == st.mp.end()) ? 0 : it->second;\n            }\n\n            bool focusMove = (focusCnt > 10 && rng.uniform01() < 0.75);\n\n            // adaptive move probabilities\n            // need large pieces => merge more (deactivate); need small pieces => split more (activate/quantile)\n            double pToggle = 0.10 + (defLarge > defSmall ? 0.05 : -0.02);\n            pToggle = max(0.05, min(0.18, pToggle));\n            double pQuant = 0.24 + (defSmall > defLarge ? 0.06 : -0.03);\n            pQuant = max(0.15, min(0.35, pQuant));\n            double pResample = 0.26;\n            double pPerturb = 1.0 - (pToggle + pQuant + pResample);\n            if (pPerturb < 0.15) { pPerturb = 0.15; pResample = 1.0 - (pToggle + pQuant + pPerturb); }\n\n            double r = rng.uniform01();\n\n            int idx = -1;\n            Line cand;\n\n            // (A) toggle activate/deactivate\n            if (r < pToggle) {\n                if (defLarge > defSmall) idx = pickActiveIndex(rng, st.lines); // merge\n                else idx = pickInactiveIndex(rng, st.lines); // split\n\n                Line old = st.lines[idx];\n                if (isInactive(old)) {\n                    // activate near focus\n                    double theta = old.theta;\n                    double cs = cos(theta), sn = sin(theta);\n                    const Point& p = st.pts[focusJ];\n                    double projp = cs * (double)p.x + sn * (double)p.y;\n                    double u = projp + rng.uniform(-700.0, 700.0);\n                    double lim = R * 0.98;\n                    u = max(-lim, min(lim, u));\n                    cand = buildLine(theta, u);\n                } else {\n                    cand = inactiveLine(rng, old.theta);\n                }\n            }\n            // (B) improved quantile split (try several angles and choose max gap)\n            else if (r < pToggle + pQuant && focusCnt >= 6) {\n                // prefer activating an inactive slot to add a split, rather than wrecking an existing line\n                if (rng.uniform01() < 0.70) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                // choose target size with largest deficit among feasible 1..min(10,focusCnt-1)\n                int tMax = min(10, focusCnt - 1);\n                int bestT = 1;\n                long long bestNeed = -1;\n                for (int d = 1; d <= tMax; d++) {\n                    long long need = max(0, st.a[d] - st.b[d]);\n                    // slight bias towards larger d (avoid producing only tiny pieces)\n                    need = need * 100 + d * 2;\n                    if (need > bestNeed) { bestNeed = need; bestT = d; }\n                }\n\n                // collect indices in this region (full scan; OK because not too frequent)\n                vector<int> region;\n                region.reserve(focusCnt);\n                for (int j = 0; j < N; j++) if (st.sig[j] == focusKey) region.push_back(j);\n                if ((int)region.size() < 6) {\n                    cand = randomActiveLineAnchored(rng, pts);\n                } else {\n                    int kpos = bestT;\n                    kpos = max(1, min((int)region.size() - 1, kpos));\n\n                    int ANG = 10;\n                    double bestTheta = rng.uniform(0.0, PI);\n                    double bestU = 0.0;\n                    double bestGap = -1.0;\n\n                    for (int t = 0; t < ANG; t++) {\n                        double theta = rng.uniform(0.0, PI);\n                        double cs = cos(theta), sn = sin(theta);\n\n                        vector<double> proj;\n                        proj.reserve(region.size());\n                        for (int j : region) proj.push_back(cs * (double)st.pts[j].x + sn * (double)st.pts[j].y);\n                        nth_element(proj.begin(), proj.begin() + kpos - 1, proj.end());\n                        double a1 = proj[kpos - 1];\n                        nth_element(proj.begin(), proj.begin() + kpos, proj.end());\n                        double a2 = proj[kpos];\n                        if (a1 > a2) swap(a1, a2);\n                        double gap = a2 - a1;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestTheta = theta;\n                            bestU = 0.5 * (a1 + a2);\n                        }\n                    }\n\n                    double lim = R * 0.98;\n                    bestU = max(-lim, min(lim, bestU));\n                    cand = buildLine(bestTheta, bestU);\n                }\n            }\n            // (C) resample active line near focus point (strong split)\n            else if (r < pToggle + pQuant + pResample || focusMove) {\n                // if we want more splitting, use inactive slot; else rewrite nearest to focus\n                if (defSmall >= defLarge && rng.uniform01() < 0.65) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                double theta = rng.uniform(0.0, PI);\n                double cs = cos(theta), sn = sin(theta);\n                const Point& p = st.pts[focusJ];\n                double projp = cs * (double)p.x + sn * (double)p.y;\n                double u = projp + rng.uniform(-800.0, 800.0);\n                double lim = R * 0.98;\n                u = max(-lim, min(lim, u));\n                cand = buildLine(theta, u);\n            }\n            // (D) perturb\n            else {\n                idx = rng.uniformInt(0, L - 1);\n                Line old = st.lines[idx];\n                cand = old;\n\n                double angleScale = 0.55 * (1.0 - prog) + 0.010;\n                double uScale = 5200.0 * (1.0 - prog) + 120.0;\n                cand.theta = wrapTheta(cand.theta + rng.uniform(-angleScale, angleScale));\n                cand.u += rng.uniform(-uScale, uScale);\n                cand.u = max(-U_INACTIVE, min(U_INACTIVE, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            }\n\n            int oldD = curD;\n            long long oldS = curS;\n\n            if (!st.applyReplaceLine(idx, cand, changedIdx, oldSig)) continue;\n\n            int newD = st.distributed();\n            long long newS = st.secondaryScore();\n\n            bool accept = false;\n            if (newD > oldD) accept = true;\n            else if (newD < oldD) {\n                // accept occasional D decrease\n                double prob = exp((double)(newD - oldD) / Td);\n                if (rng.uniform01() < prob) accept = true;\n            } else {\n                long long dS = newS - oldS;\n                if (dS >= 0) accept = true;\n                else {\n                    double x = (double)dS / Ts;\n                    if (x > -60) {\n                        double prob = exp(x);\n                        if (rng.uniform01() < prob) accept = true;\n                    }\n                }\n            }\n\n            if (accept) {\n                st.lines[idx] = cand;\n                curD = newD;\n                curS = newS;\n                if (curD > bestD || (curD == bestD && curS > bestS)) {\n                    bestD = curD;\n                    bestS = curS;\n                    bestLines = st.lines;\n                }\n            } else {\n                st.rollbackReplaceLine(changedIdx, oldSig);\n            }\n        }\n\n        // Postprocess: merge repair\n        double remAll = TIME_LIMIT - timer.elapsedSec();\n        double postBudget = min(0.12, max(0.03, remAll * 0.18));\n        bestLines = deactivateSweep(bestLines, pts, a, rng, postBudget);\n\n        // Evaluate postprocessed\n        {\n            State tmp;\n            tmp.N = N; tmp.L = L; tmp.pts = pts; tmp.a = a; tmp.lines = bestLines;\n            if (tmp.buildInitialSignatures()) {\n                bestD = tmp.distributed();\n                bestS = tmp.secondaryScore();\n            }\n        }\n\n        if (bestD > globalBestD || (bestD == globalBestD && bestS > globalBestS)) {\n            globalBestD = bestD;\n            globalBestS = bestS;\n            globalBestLines = bestLines;\n        }\n    }\n\n    if (globalBestLines.empty()) {\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n    cout << (int)globalBestLines.size() << \"\\n\";\n    for (auto& Lx : globalBestLines) {\n        cout << Lx.px << \" \" << Lx.py << \" \" << Lx.qx << \" \" << Lx.qy << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    explicit XorShift(uint64_t seed = 0) { x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstatic inline uint64_t maskRange64(int l, int r) {\n    if (l > r) return 0;\n    uint64_t left = (~0ULL) << l;\n    uint64_t right = (r == 63) ? ~0ULL : ((1ULL << (r + 1)) - 1ULL);\n    return left & right;\n}\n\nstruct Bits128 {\n    uint64_t lo = 0, hi = 0;\n    inline void set(int idx) {\n        if (idx < 64) lo |= 1ULL << idx;\n        else hi |= 1ULL << (idx - 64);\n    }\n    inline bool test(int idx) const {\n        if (idx < 64) return (lo >> idx) & 1ULL;\n        else return (hi >> (idx - 64)) & 1ULL;\n    }\n    inline void reset(int idx) {\n        if (idx < 64) lo &= ~(1ULL << idx);\n        else hi &= ~(1ULL << (idx - 64));\n    }\n    inline bool any() const { return lo || hi; }\n    inline Bits128 operator&(const Bits128& o) const { return Bits128{lo & o.lo, hi & o.hi}; }\n\n    inline bool anyInRange(int l, int r) const {\n        if (l > r) return false;\n        uint64_t mlo = 0, mhi = 0;\n        if (l < 64) {\n            int rr = min(r, 63);\n            mlo = maskRange64(l, rr);\n        }\n        if (r >= 64) {\n            int ll = max(l, 64) - 64;\n            int rr = r - 64;\n            mhi = maskRange64(ll, rr);\n        }\n        return (lo & mlo) || (hi & mhi);\n    }\n    inline int popcount() const { return __builtin_popcountll(lo) + __builtin_popcountll(hi); }\n};\n\nstruct Point { int x, y; };\n\nstruct Move {\n    Point p1, p2, p3, p4;\n    bool isAxis = true;\n    double val = -1e100;\n};\n\nstruct Params {\n    int topP = 220;\n    int midP = 900;\n    int randP = 60;\n    double noise = 0.02;\n\n    // normal mode (progressive)\n    double alphaStart = 0.55, alphaEnd = 0.28;     // perimeter penalty\n    double betaStart  = 2.00, betaEnd  = 0.60;     // connectivity bonus\n\n    // fill fallback\n    double fillAlpha = 0.85;\n    double fillBeta  = 1.20;\n    double fillWeightCoef = 0.20;\n};\n\nstruct State {\n    int N;\n    int shiftV;           // N-1\n    int U, V;             // 2N-1\n\n    array<uint64_t, 61> dotRow{}; // y -> bits x\n    array<uint64_t, 61> dotCol{}; // x -> bits y\n\n    vector<Bits128> diagVdots; // vIdx -> bits u\n    vector<Bits128> antiUdots; // u -> bits vIdx\n\n    array<uint64_t, 61> hUsed{}; // y -> bits x seg (x,y)-(x+1,y)\n    array<uint64_t, 61> vUsed{}; // x -> bits y seg (x,y)-(x,y+1)\n\n    // diagonal segment usage as bitmasks per line:\n    // d1: slope +1, indexed by vIdx = x-y+shiftV, bit = position along that diagonal\n    // d2: slope -1, indexed by u = x+y, bit = position along that anti-diagonal\n    vector<uint64_t> d1SegUsed; // size V\n    vector<uint64_t> d2SegUsed; // size U\n\n    array<uint8_t, 61> rowCnt{};\n    array<uint8_t, 61> colCnt{};\n    vector<uint8_t> diagVCnt;\n    vector<uint8_t> antiUCnt;\n\n    int dots = 0;\n    long long sumW = 0;\n\n    State(int N_=0): N(N_) {}\n\n    inline bool hasDot(int x, int y) const { return (dotRow[y] >> x) & 1ULL; }\n\n    inline void addDot(int x, int y) {\n        dotRow[y] |= 1ULL << x;\n        dotCol[x] |= 1ULL << y;\n        rowCnt[y]++; colCnt[x]++;\n        int u = x + y;\n        int vIdx = x - y + shiftV;\n        diagVdots[vIdx].set(u);\n        antiUdots[u].set(vIdx);\n        diagVCnt[vIdx]++; antiUCnt[u]++;\n        dots++;\n    }\n\n    inline bool rowHasDotBetween(int y, int x1, int x2) const {\n        int l = min(x1, x2) + 1;\n        int r = max(x1, x2) - 1;\n        if (l > r) return false;\n        return (dotRow[y] & maskRange64(l, r)) != 0;\n    }\n    inline bool colHasDotBetween(int x, int y1, int y2) const {\n        int l = min(y1, y2) + 1;\n        int r = max(y1, y2) - 1;\n        if (l > r) return false;\n        return (dotCol[x] & maskRange64(l, r)) != 0;\n    }\n    inline uint64_t segMaskX(int x1, int x2) const {\n        int l = min(x1, x2);\n        int r = max(x1, x2) - 1;\n        return maskRange64(l, r);\n    }\n    inline uint64_t segMaskY(int y1, int y2) const {\n        int l = min(y1, y2);\n        int r = max(y1, y2) - 1;\n        return maskRange64(l, r);\n    }\n\n    // diagonal line lengths (number of points)\n    inline int lenD1(int vIdx) const {\n        int d = vIdx - shiftV;\n        return N - abs(d);\n    }\n    inline int lenD2(int u) const {\n        return N - abs(u - (N - 1));\n    }\n\n    inline int posD1(int vIdx, int x, int y) const {\n        int d = vIdx - shiftV;\n        // start is (d,0) if d>=0 else (0,-d)\n        // along line, (x,y) increases together; position equals y if d>=0 else x\n        return (d >= 0) ? y : x;\n    }\n    inline int posD2(int u, int x, int y) const {\n        int startX = (u < N) ? 0 : (u - (N - 1));\n        (void)y;\n        return x - startX;\n    }\n\n    inline bool d1FreeRange(int vIdx, int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return true;\n        uint64_t m = maskRange64(l, r);\n        return (d1SegUsed[vIdx] & m) == 0;\n    }\n    inline bool d2FreeRange(int u, int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return true;\n        uint64_t m = maskRange64(l, r);\n        return (d2SegUsed[u] & m) == 0;\n    }\n    inline void d1MarkRange(int vIdx, int posA, int posB) {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return;\n        d1SegUsed[vIdx] |= maskRange64(l, r);\n    }\n    inline void d2MarkRange(int u, int posA, int posB) {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        if (l > r) return;\n        d2SegUsed[u] |= maskRange64(l, r);\n    }\n\n    inline Point uvToXY(int u, int vIdx) const {\n        int v = vIdx - shiftV;\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    inline bool canAxisRect(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 || y1 == y2) return false;\n        if (hasDot(x1, y1)) return false;\n        if (!hasDot(x2, y1) || !hasDot(x2, y2) || !hasDot(x1, y2)) return false;\n\n        if (rowHasDotBetween(y1, x1, x2)) return false;\n        if (rowHasDotBetween(y2, x1, x2)) return false;\n        if (colHasDotBetween(x1, y1, y2)) return false;\n        if (colHasDotBetween(x2, y1, y2)) return false;\n\n        uint64_t hm = segMaskX(x1, x2);\n        if ((hUsed[y1] & hm) || (hUsed[y2] & hm)) return false;\n        uint64_t vm = segMaskY(y1, y2);\n        if ((vUsed[x1] & vm) || (vUsed[x2] & vm)) return false;\n\n        return true;\n    }\n\n    inline void applyAxisRect(const Move& mv) {\n        int x1 = mv.p1.x, y1 = mv.p1.y;\n        int x2 = mv.p2.x, y2 = mv.p3.y;\n\n        uint64_t hm = segMaskX(x1, x2);\n        hUsed[y1] |= hm;\n        hUsed[y2] |= hm;\n        uint64_t vm = segMaskY(y1, y2);\n        vUsed[x1] |= vm;\n        vUsed[x2] |= vm;\n\n        addDot(x1, y1);\n    }\n\n    inline bool canDiagRect(int x1, int y1, int u2, int v2Idx) const {\n        if (hasDot(x1, y1)) return false;\n        int u1 = x1 + y1;\n        int v1Idx = x1 - y1 + shiftV;\n\n        // condition 2: no dots on perimeter in (u,v) space\n        if (diagVdots[v1Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (diagVdots[v2Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (antiUdots[u1].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n        if (antiUdots[u2].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n\n        Point p1 = {x1, y1};\n        Point p2 = uvToXY(u2, v1Idx);\n        Point p3 = uvToXY(u2, v2Idx);\n        Point p4 = uvToXY(u1, v2Idx);\n\n        auto in = [&](Point p) { return 0 <= p.x && p.x < N && 0 <= p.y && p.y < N; };\n        if (!in(p2) || !in(p3) || !in(p4)) return false;\n        if (!hasDot(p2.x, p2.y) || !hasDot(p3.x, p3.y) || !hasDot(p4.x, p4.y)) return false;\n\n        // condition 3: no shared segments with existing diagonal segments\n        // edges: p1-p2 and p3-p4 are on d1 (v fixed); p2-p3 and p4-p1 are on d2 (u fixed)\n        int v1 = v1Idx;\n        int v2 = v2Idx;\n\n        int pos1_v1 = posD1(v1, p1.x, p1.y);\n        int pos2_v1 = posD1(v1, p2.x, p2.y);\n        if (!d1FreeRange(v1, pos1_v1, pos2_v1)) return false;\n\n        int pos3_v2 = posD1(v2, p3.x, p3.y);\n        int pos4_v2 = posD1(v2, p4.x, p4.y);\n        if (!d1FreeRange(v2, pos3_v2, pos4_v2)) return false;\n\n        int uA = u2;\n        int pos2_u2 = posD2(uA, p2.x, p2.y);\n        int pos3_u2 = posD2(uA, p3.x, p3.y);\n        if (!d2FreeRange(uA, pos2_u2, pos3_u2)) return false;\n\n        int uB = u1;\n        int pos4_u1 = posD2(uB, p4.x, p4.y);\n        int pos1_u1 = posD2(uB, p1.x, p1.y);\n        if (!d2FreeRange(uB, pos4_u1, pos1_u1)) return false;\n\n        return true;\n    }\n\n    inline void applyDiagRect(const Move& mv) {\n        // mark segments on corresponding diagonal lines\n        int u1 = mv.p1.x + mv.p1.y;\n        int u2 = mv.p2.x + mv.p2.y;\n        int v1 = mv.p1.x - mv.p1.y + shiftV;\n        int v2 = mv.p3.x - mv.p3.y + shiftV;\n\n        // p1-p2 on d1(v1)\n        d1MarkRange(v1, posD1(v1, mv.p1.x, mv.p1.y), posD1(v1, mv.p2.x, mv.p2.y));\n        // p2-p3 on d2(u2)\n        d2MarkRange(u2, posD2(u2, mv.p2.x, mv.p2.y), posD2(u2, mv.p3.x, mv.p3.y));\n        // p3-p4 on d1(v2)\n        d1MarkRange(v2, posD1(v2, mv.p3.x, mv.p3.y), posD1(v2, mv.p4.x, mv.p4.y));\n        // p4-p1 on d2(u1)\n        d2MarkRange(u1, posD2(u1, mv.p4.x, mv.p4.y), posD2(u1, mv.p1.x, mv.p1.y));\n\n        addDot(mv.p1.x, mv.p1.y);\n    }\n};\n\nstruct Result {\n    vector<array<int, 8>> ops;\n    long long sumW = 0;\n    int dots = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int c = (N - 1) / 2;\n\n    vector<vector<int>> w(N, vector<int>(N, 0)); // w[x][y]\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) {\n        int dx = x - c, dy = y - c;\n        w[x][y] = dx * dx + dy * dy + 1;\n    }\n\n    vector<Point> initial(M);\n    for (int i = 0; i < M; i++) cin >> initial[i].x >> initial[i].y;\n\n    vector<Point> allPoints;\n    allPoints.reserve(N * N);\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) allPoints.push_back({x, y});\n    sort(allPoints.begin(), allPoints.end(), [&](const Point& a, const Point& b) {\n        int wa = w[a.x][a.y], wb = w[b.x][b.y];\n        if (wa != wb) return wa > wb;\n        if (a.x != b.x) return a.x < b.x;\n        return a.y < b.y;\n    });\n\n    auto start = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n    };\n\n    auto perimeterAxis = [&](int x1, int y1, int x2, int y2) -> int {\n        return 2 * (abs(x2 - x1) + abs(y2 - y1));\n    };\n    auto perimeterDiag = [&](const Point& p1, const Point& p2, const Point& p3) -> int {\n        int a = abs(p2.x - p1.x);\n        int b = abs(p3.x - p2.x);\n        return 2 * (a + b);\n    };\n\n    auto runOnce = [&](uint64_t seed, const Params& par) -> Result {\n        XorShift rng(seed);\n\n        State st(N);\n        st.shiftV = N - 1;\n        st.U = 2 * N - 1;\n        st.V = 2 * N - 1;\n        st.diagVdots.assign(st.V, Bits128{});\n        st.antiUdots.assign(st.U, Bits128{});\n        st.d1SegUsed.assign(st.V, 0ULL);\n        st.d2SegUsed.assign(st.U, 0ULL);\n        st.diagVCnt.assign(st.V, 0);\n        st.antiUCnt.assign(st.U, 0);\n\n        for (auto &x : st.dotRow) x = 0;\n        for (auto &x : st.dotCol) x = 0;\n        for (auto &x : st.hUsed) x = 0;\n        for (auto &x : st.vUsed) x = 0;\n        for (auto &x : st.rowCnt) x = 0;\n        for (auto &x : st.colCnt) x = 0;\n        st.dots = 0;\n        st.sumW = 0;\n\n        for (auto p : initial) {\n            st.addDot(p.x, p.y);\n            st.sumW += w[p.x][p.y];\n        }\n\n        vector<array<int, 8>> ops;\n        ops.reserve(N * N);\n\n        auto collectP1 = [&](int P) {\n            vector<Point> res;\n            res.reserve(P + par.randP);\n            for (const auto& p : allPoints) {\n                if ((int)res.size() >= P) break;\n                if (!st.hasDot(p.x, p.y)) res.push_back(p);\n            }\n            for (int i = 0; i < par.randP; i++) {\n                for (int t = 0; t < 40; t++) {\n                    int x = rng.nextInt(0, N - 1);\n                    int y = rng.nextInt(0, N - 1);\n                    if (!st.hasDot(x, y)) { res.push_back({x, y}); break; }\n                }\n            }\n            return res;\n        };\n\n        auto evalMove = [&](const Point& p1, int per, bool fillMode) -> double {\n            int x1 = p1.x, y1 = p1.y;\n            int u1 = x1 + y1;\n            int v1 = x1 - y1 + st.shiftV;\n            int conn = (int)st.rowCnt[y1] + (int)st.colCnt[x1] + (int)st.diagVCnt[v1] + (int)st.antiUCnt[u1];\n\n            double progress = (double)ops.size() / (double)max(1, (N * N - M));\n            progress = min(1.0, max(0.0, progress));\n\n            double alpha, beta, wcoef;\n            if (!fillMode) {\n                alpha = par.alphaStart * (1.0 - progress) + par.alphaEnd * progress;\n                beta  = par.betaStart  * (1.0 - progress) + par.betaEnd  * progress;\n                wcoef = 1.0;\n            } else {\n                alpha = par.fillAlpha;\n                beta  = par.fillBeta;\n                wcoef = par.fillWeightCoef;\n            }\n            return wcoef * (double)w[x1][y1] + beta * (double)conn - alpha * (double)per + par.noise * rng.nextDouble();\n        };\n\n        auto findBestMove = [&](Move& best, bool fillMode) -> bool {\n            best.val = -1e100;\n            bool found = false;\n\n            auto tryList = [&](int P) {\n                auto p1s = collectP1(P);\n                for (const auto& p1 : p1s) {\n                    int x1 = p1.x, y1 = p1.y;\n                    if (st.hasDot(x1, y1)) continue;\n\n                    // axis candidates\n                    uint64_t yMask = st.dotCol[x1];\n                    while (yMask) {\n                        int y2 = __builtin_ctzll(yMask);\n                        yMask &= yMask - 1;\n                        if (y2 == y1) continue;\n\n                        uint64_t inter = st.dotRow[y1] & st.dotRow[y2];\n                        inter &= ~(1ULL << x1);\n                        while (inter) {\n                            int x2 = __builtin_ctzll(inter);\n                            inter &= inter - 1;\n                            if (x2 == x1) continue;\n\n                            if (!st.canAxisRect(x1, y1, x2, y2)) continue;\n\n                            Move mv;\n                            mv.isAxis = true;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = {x2, y1};\n                            mv.p3 = {x2, y2};\n                            mv.p4 = {x1, y2};\n\n                            int per = perimeterAxis(x1, y1, x2, y2);\n                            double val = evalMove(p1, per, fillMode);\n                            if (val > best.val) { best = mv; best.val = val; found = true; }\n                        }\n                    }\n\n                    // diagonal candidates\n                    int u1 = x1 + y1;\n                    int v1Idx = x1 - y1 + st.shiftV;\n\n                    Bits128 vMask = st.antiUdots[u1];\n                    uint64_t vlo = vMask.lo, vhi = vMask.hi;\n\n                    auto handleV2 = [&](int v2Idx) {\n                        if (v2Idx == v1Idx) return;\n                        Bits128 interU = st.diagVdots[v1Idx] & st.diagVdots[v2Idx];\n                        if (u1 < 128) interU.reset(u1);\n                        if (!interU.any()) return;\n\n                        uint64_t ulo = interU.lo, uhi = interU.hi;\n                        auto handleU2 = [&](int u2) {\n                            if (u2 == u1) return;\n                            if (!st.canDiagRect(x1, y1, u2, v2Idx)) return;\n\n                            Point p2 = st.uvToXY(u2, v1Idx);\n                            Point p3 = st.uvToXY(u2, v2Idx);\n                            Point p4 = st.uvToXY(u1, v2Idx);\n\n                            Move mv;\n                            mv.isAxis = false;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = p2;\n                            mv.p3 = p3;\n                            mv.p4 = p4;\n\n                            int per = perimeterDiag(mv.p1, mv.p2, mv.p3);\n                            double val = evalMove(p1, per, fillMode);\n                            if (val > best.val) { best = mv; best.val = val; found = true; }\n                        };\n\n                        while (ulo) { int b = __builtin_ctzll(ulo); ulo &= ulo - 1; handleU2(b); }\n                        while (uhi) { int b = __builtin_ctzll(uhi); uhi &= uhi - 1; handleU2(64 + b); }\n                    };\n\n                    while (vlo) { int b = __builtin_ctzll(vlo); vlo &= vlo - 1; handleV2(b); }\n                    while (vhi) { int b = __builtin_ctzll(vhi); vhi &= vhi - 1; handleV2(64 + b); }\n                }\n            };\n\n            tryList(fillMode ? par.midP : par.topP);\n            if (found) return true;\n            tryList(fillMode ? (N * N) : par.midP);\n            return found;\n        };\n\n        while (elapsedSec() < 4.92) {\n            Move best;\n            if (!findBestMove(best, /*fillMode=*/false)) {\n                // fallback: favor short perimeter / connectivity to keep going\n                if (!findBestMove(best, /*fillMode=*/true)) break;\n            }\n\n            if (best.isAxis) st.applyAxisRect(best);\n            else st.applyDiagRect(best);\n\n            st.sumW += w[best.p1.x][best.p1.y];\n\n            ops.push_back({best.p1.x, best.p1.y,\n                           best.p2.x, best.p2.y,\n                           best.p3.x, best.p3.y,\n                           best.p4.x, best.p4.y});\n        }\n\n        Result res;\n        res.ops = std::move(ops);\n        res.sumW = st.sumW;\n        res.dots = st.dots;\n        return res;\n    };\n\n    // More restarts, pick best by sumW (true objective proxy)\n    vector<Params> plist;\n    {\n        Params p;\n        p.topP = 220; p.midP = 900; p.randP = 60;\n        p.alphaStart = 0.58; p.alphaEnd = 0.30;\n        p.betaStart = 2.2; p.betaEnd = 0.7;\n        p.fillAlpha = 0.90; p.fillBeta = 1.25; p.fillWeightCoef = 0.15;\n        p.noise = 0.02;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 300; p.midP = 1200; p.randP = 70;\n        p.alphaStart = 0.52; p.alphaEnd = 0.26;\n        p.betaStart = 1.8; p.betaEnd = 0.55;\n        p.fillAlpha = 0.85; p.fillBeta = 1.15; p.fillWeightCoef = 0.20;\n        p.noise = 0.025;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 180; p.midP = 800; p.randP = 50;\n        p.alphaStart = 0.62; p.alphaEnd = 0.32;\n        p.betaStart = 2.4; p.betaEnd = 0.80;\n        p.fillAlpha = 0.95; p.fillBeta = 1.30; p.fillWeightCoef = 0.10;\n        p.noise = 0.018;\n        plist.push_back(p);\n    }\n\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result bestRes;\n    bestRes.sumW = -1;\n\n    int trial = 0;\n    while (elapsedSec() < 4.93) {\n        const Params& par = plist[trial % (int)plist.size()];\n        uint64_t seed = baseSeed + 1000003ULL * (uint64_t)trial;\n        auto res = runOnce(seed, par);\n        if (res.sumW > bestRes.sumW || (res.sumW == bestRes.sumW && res.ops.size() > bestRes.ops.size())) {\n            bestRes = std::move(res);\n        }\n        trial++;\n    }\n\n    cout << bestRes.ops.size() << \"\\n\";\n    for (auto &a : bestRes.ops) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << a[i];\n        }\n        cout << \"\\n\";\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int M = 100;\n\n// ---------- RNG ----------\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n    inline double next_double01() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\n// ---------- Board ----------\nstruct Board {\n    array<uint8_t, M> a{}; // 0 empty, 1..3 flavors\n\n    inline uint8_t get(int r, int c) const { return a[r * N + c]; }\n    inline void set(int r, int c, uint8_t v) { a[r * N + c] = v; }\n\n    // dir: 0=F(up),1=B(down),2=L(left),3=R(right)\n    inline void tilt(int dir) {\n        if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                int base = r * N;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = (c < k ? tmp[c] : 0);\n            }\n        } else if (dir == 3) { // R\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0;\n                int base = r * N;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = 0;\n                for (int i = 0; i < k; i++) a[base + (N - 1 - i)] = tmp[i];\n            }\n        } else if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = (r < k ? tmp[r] : 0);\n            }\n        } else { // B\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = 0;\n                for (int i = 0; i < k; i++) a[(N - 1 - i) * N + c] = tmp[i];\n            }\n        }\n    }\n\n    inline void place_by_p(int p, uint8_t flavor) {\n        int cnt = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                if (++cnt == p) { a[i] = flavor; return; }\n            }\n        }\n    }\n\n    inline void place_random_empty(uint8_t flavor, XorShift64 &rng) {\n        // Reservoir sampling: single pass, uniform among empties.\n        int chosen = -1;\n        int seen = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] != 0) continue;\n            seen++;\n            if (rng.next_int(seen) == 0) chosen = i;\n        }\n        if (chosen != -1) a[chosen] = flavor;\n    }\n\n    inline int filled_count() const {\n        int f = 0;\n        for (int i = 0; i < M; i++) f += (a[i] != 0);\n        return f;\n    }\n};\n\n// ---------- Precomputed neighbors / coords ----------\nstatic array<array<int, 4>, M> nbr{};\nstatic array<uint8_t, M> deg{};\nstatic array<uint8_t, M> RR{}, CC{};\nstatic array<uint8_t, M> emptyCornerCloseness{}; // closeness to insertion corner (9,0): 18 - dist\n\nstatic inline void init_pre() {\n    for (int i = 0; i < M; i++) {\n        int r = i / N, c = i % N;\n        RR[i] = (uint8_t)r;\n        CC[i] = (uint8_t)c;\n\n        int d = 0;\n        auto add = [&](int nr, int nc) {\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return;\n            nbr[i][d++] = nr * N + nc;\n        };\n        add(r - 1, c);\n        add(r + 1, c);\n        add(r, c - 1);\n        add(r, c + 1);\n        deg[i] = (uint8_t)d;\n\n        int dist = abs(r - 9) + abs(c - 0);\n        emptyCornerCloseness[i] = (uint8_t)(18 - dist); // 0..18\n    }\n}\n\n// ---------- Features (single pass-ish) ----------\nstruct Features {\n    int same_adj = 0;\n    int diff_adj = 0;\n    int empty_adj = 0;\n    long long variance = 0;      // smaller is better\n    long long separation = 0;    // larger is better\n    int empty_corner = 0;        // larger is better\n};\n\nstatic inline Features compute_features(const Board &b) {\n    long long cnt[4] = {0,0,0,0};\n    long long sumr[4] = {0,0,0,0}, sumc[4] = {0,0,0,0};\n    long long sumr2[4] = {0,0,0,0}, sumc2[4] = {0,0,0,0};\n\n    Features ft;\n\n    // cell stats + empty corner score\n    for (int i = 0; i < M; i++) {\n        uint8_t v = b.a[i];\n        if (!v) {\n            ft.empty_corner += emptyCornerCloseness[i];\n            continue;\n        }\n        int r = RR[i], c = CC[i];\n        cnt[v]++;\n        sumr[v] += r;\n        sumc[v] += c;\n        sumr2[v] += 1LL * r * r;\n        sumc2[v] += 1LL * c * c;\n    }\n\n    // adjacency (right/down only)\n    for (int r = 0; r < N; r++) {\n        int base = r * N;\n        for (int c = 0; c < N; c++) {\n            uint8_t v = b.a[base + c];\n            if (c + 1 < N) {\n                uint8_t u = b.a[base + (c + 1)];\n                if (!v && !u) ft.empty_adj++;\n                else if (v && u) {\n                    if (v == u) ft.same_adj++;\n                    else ft.diff_adj++;\n                }\n            }\n            if (r + 1 < N) {\n                uint8_t u = b.a[base + N + c];\n                if (!v && !u) ft.empty_adj++;\n                else if (v && u) {\n                    if (v == u) ft.same_adj++;\n                    else ft.diff_adj++;\n                }\n            }\n        }\n    }\n\n    // variance-like compactness (scaled by cnt to avoid division)\n    for (int f = 1; f <= 3; f++) {\n        if (cnt[f] <= 1) continue;\n        long long vr = sumr2[f] * cnt[f] - sumr[f] * sumr[f];\n        long long vc = sumc2[f] * cnt[f] - sumc[f] * sumc[f];\n        ft.variance += vr + vc;\n    }\n\n    // centroid separation numerator (also without division)\n    for (int i = 1; i <= 3; i++) for (int j = i + 1; j <= 3; j++) {\n        if (cnt[i] == 0 || cnt[j] == 0) continue;\n        ft.separation += llabs(sumr[i] * cnt[j] - sumr[j] * cnt[i]);\n        ft.separation += llabs(sumc[i] * cnt[j] - sumc[j] * cnt[i]);\n    }\n\n    return ft;\n}\n\n// ---------- Component squares (true objective proxy) ----------\nstatic inline long long comp_sq_sum(const Board &b) {\n    bool vis[M];\n    memset(vis, 0, sizeof(vis));\n    int q[M];\n\n    long long sumsq = 0;\n    for (int i = 0; i < M; i++) {\n        if (b.a[i] == 0 || vis[i]) continue;\n        uint8_t col = b.a[i];\n        int head = 0, tail = 0;\n        vis[i] = true;\n        q[tail++] = i;\n        int cnt = 0;\n        while (head < tail) {\n            int v = q[head++];\n            cnt++;\n            for (int k = 0; k < deg[v]; k++) {\n                int to = nbr[v][k];\n                if (!vis[to] && b.a[to] == col) {\n                    vis[to] = true;\n                    q[tail++] = to;\n                }\n            }\n        }\n        sumsq += 1LL * cnt * cnt;\n    }\n    return sumsq;\n}\n\nstatic inline long long full_eval(const Board &b) {\n    int filled = b.filled_count();\n    long long cs = comp_sq_sum(b);\n    Features ft = compute_features(b);\n\n    // Stage weights (tuned to reduce worst-case regressions):\n    long long wComp = (filled < 30 ? 450 : (filled < 70 ? 1650 : 3700));\n    long long wSame = (filled < 30 ? 120 : (filled < 70 ? 90   : 70));\n    long long wDiff = (filled < 30 ? 200 : (filled < 70 ? 140  : 110));\n    long long wVar  = (filled < 30 ? 3   : (filled < 70 ? 2    : 1));\n    long long wSep  = (filled < 30 ? 6   : (filled < 70 ? 4    : 2));\n    long long wEC   = (filled < 30 ? 140 : (filled < 70 ? 80   : 25));\n    long long wEmpA = 5;\n\n    // Note: variance is a penalty, separation/empty_corner are bonuses.\n    return cs * wComp\n         + 1LL * ft.same_adj * wSame\n         - 1LL * ft.diff_adj * wDiff\n         - 1LL * ft.variance * wVar\n         + 1LL * ft.separation * wSep\n         + 1LL * ft.empty_corner * wEC\n         + 1LL * ft.empty_adj * wEmpA;\n}\n\nstatic inline int fast_eval(const Board &b) {\n    // Cheap proxy for rollout decision-making (no BFS).\n    Features ft = compute_features(b);\n    // Make diff boundaries very undesirable in rollouts.\n    return ft.same_adj * 110\n         - ft.diff_adj * 140\n         - (int)min<long long>(2000000000LL, ft.variance / 2000) * 3\n         + (int)min<long long>(2000000000LL, ft.separation / 400) * 4\n         + ft.empty_corner * 70\n         + ft.empty_adj * 4;\n}\n\nstatic inline int rollout_policy(const Board &b, XorShift64 &rng) {\n    // epsilon-greedy\n    if (rng.next_double01() < 0.06) return rng.next_int(4);\n\n    int best = INT_MIN;\n    int bestDirs[4];\n    int k = 0;\n    for (int d = 0; d < 4; d++) {\n        Board nb = b;\n        nb.tilt(d);\n        int v = fast_eval(nb);\n        if (v > best) {\n            best = v;\n            k = 0;\n            bestDirs[k++] = d;\n        } else if (v == best) {\n            bestDirs[k++] = d;\n        }\n    }\n    return bestDirs[rng.next_int(k)];\n}\n\nstatic inline long long simulate_rollout(Board b, int t_next, int depth,\n                                        const array<uint8_t, 100> &flv,\n                                        XorShift64 &rng) {\n    for (int step = 0; step < depth && t_next < 100; step++, t_next++) {\n        b.place_random_empty(flv[t_next], rng);\n        if (t_next == 99) break;\n        int d = rollout_policy(b, rng);\n        b.tilt(d);\n    }\n    return full_eval(b);\n}\n\nstatic inline char dir_char(int d) {\n    if (d == 0) return 'F';\n    if (d == 1) return 'B';\n    if (d == 2) return 'L';\n    return 'R';\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_pre();\n\n    array<uint8_t, 100> flv{};\n    for (int i = 0; i < 100; i++) {\n        int x; cin >> x;\n        flv[i] = (uint8_t)x;\n    }\n\n    // deterministic seed from flavor sequence\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < 100; i++) seed = (seed ^ flv[i]) * 1099511628211ULL;\n    XorShift64 rng(seed);\n\n    Board cur;\n\n    auto t_start = chrono::steady_clock::now();\n    const double TL = 1.985;\n\n    for (int t = 0; t < 100; t++) {\n        int p; cin >> p;\n        cur.place_by_p(p, flv[t]);\n\n        if (t == 99) break;\n\n        Board candB[4];\n        long double sum[4];\n        int cnt[4];\n\n        for (int d = 0; d < 4; d++) {\n            candB[d] = cur;\n            candB[d].tilt(d);\n            sum[d] = (long double)full_eval(candB[d]);\n            cnt[d] = 1;\n        }\n\n        int remainMoves = 99 - t;\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n        double left = TL - elapsed;\n        if (left < 0) left = 0;\n\n        // Spend more early, less late.\n        double base = (remainMoves > 0 ? left / remainMoves : 0.0);\n        double earlyFactor = 1.25 - 0.75 * (double)t / 99.0; // 1.25 -> 0.50\n        double budget = base * earlyFactor * 0.90;\n\n        budget = min(budget, 0.090);\n        budget = max(budget, 0.0015);\n\n        int remain = 99 - t;\n        int depth = (remain >= 70 ? 8 : (remain >= 40 ? 6 : (remain >= 20 ? 4 : 3)));\n        depth = min(depth, 100 - (t + 1));\n\n        auto move_end = chrono::steady_clock::now() + chrono::duration<double>(budget);\n\n        // Common-random-numbers iterations: one RNG seed per iteration, reused for all 4 candidates.\n        while (chrono::steady_clock::now() < move_end) {\n            uint64_t s = rng.next_u64();\n            for (int d = 0; d < 4; d++) {\n                XorShift64 local(s);\n                long long v = simulate_rollout(candB[d], t + 1, depth, flv, local);\n                sum[d] += (long double)v;\n                cnt[d] += 1;\n            }\n        }\n\n        int bestDir = 0;\n        long double bestVal = -1e300L;\n        for (int d = 0; d < 4; d++) {\n            long double avg = sum[d] / (long double)cnt[d];\n            if (avg > bestVal) {\n                bestVal = avg;\n                bestDir = d;\n            }\n        }\n\n        cout << dir_char(bestDir) << '\\n' << flush;\n        cur.tilt(bestDir);\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\n#include <csignal>\n#include <Eigen/Dense>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u64() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstatic long long C2(long long x){ return x*(x-1)/2; }\nstatic long long C3(long long x){ return x*(x-1)*(x-2)/6; }\n\nstatic vector<double> binom_pmf(int n, double p) {\n    vector<double> pmf(n+1, 0.0);\n    if (n==0) { pmf[0]=1.0; return pmf; }\n    if (p<=0.0) { pmf[0]=1.0; return pmf; }\n    if (p>=1.0) { pmf[n]=1.0; return pmf; }\n    double q = 1.0 - p;\n    pmf[0] = pow(q, n);\n    double ratio = p / q;\n    for (int k=1;k<=n;k++){\n        pmf[k] = pmf[k-1] * (double)(n-k+1) / (double)k * ratio;\n    }\n    return pmf;\n}\n\nstatic int choose_ms(double eps){\n    if (eps <= 0.15) return 1;\n    if (eps <= 0.25) return 2;\n    if (eps <= 0.33) return 3;\n    if (eps <= 0.37) return 4;\n    return 5;\n}\n\nstatic int chooseN_init(int M, double eps){\n    // Slightly more aggressive for tiny eps, more conservative for large eps.\n    if (eps <= 0.00) return 13; // p(13)=101 >= 100\n    if (eps <= 0.01) return (M <= 90 ? 13 : 14);\n    if (eps <= 0.02) return 14;\n    if (eps <= 0.05) return 18;\n    if (eps <= 0.10) return 26;\n    if (eps <= 0.15) return 34;\n    if (eps <= 0.20) return 45;\n    if (eps <= 0.25) return 60;\n    if (eps <= 0.30) return 80;\n    if (eps <= 0.32) return 92;\n    return 100;\n}\n\nstruct Part {\n    vector<int> sz;     // clique sizes descending\n    int E = 0;          // sum C2(sz)\n    long long T_in = 0; // sum C3(sz)\n    long long S2 = 0;   // sum sz^2\n    long long S3 = 0;   // sum sz^3\n    int B = 0;\n    int mx = 0, mn = 0;\n};\n\nstatic Part make_part(const vector<int>& sz){\n    Part p;\n    p.sz = sz;\n    p.B = (int)sz.size();\n    p.mx = sz.empty() ? 0 : sz[0];\n    p.mn = sz.empty() ? 0 : sz.back();\n    long long E=0, T=0, S2=0, S3=0;\n    for(int x: sz){\n        E += C2(x);\n        T += C3(x);\n        S2 += 1LL*x*x;\n        S3 += 1LL*x*x*x;\n    }\n    p.E = (int)E;\n    p.T_in = T;\n    p.S2 = S2;\n    p.S3 = S3;\n    return p;\n}\n\nstatic string key_of(const vector<int>& v){\n    string s;\n    s.reserve(v.size() * 3);\n    for (int i=0;i<(int)v.size();i++){\n        if(i) s.push_back('-');\n        s += to_string(v[i]);\n    }\n    return s;\n}\n\nstatic double part_dist(const Part& a, const Part& b, int N, int L, long long totalTri){\n    auto norm = [](double x, double s){ return x / (s > 0 ? s : 1.0); };\n    double dE  = norm(abs(a.E - b.E), (double)L);\n    double dT  = norm((double)llabs(a.T_in - b.T_in), (double)max(1LL, totalTri));\n    double dS2 = norm((double)llabs(a.S2 - b.S2), (double)max(1LL, 1LL*N*N));\n    double dS3 = norm((double)llabs(a.S3 - b.S3), (double)max(1LL, 1LL*N*N*N));\n    double dB  = abs(a.B - b.B) / (double)max(1, N);\n    double dmx = abs(a.mx - b.mx) / (double)max(1, N);\n    double dmn = abs(a.mn - b.mn) / (double)max(1, N);\n    return 2.0*dE + 2.0*dT + 0.8*dS2 + 0.4*dS3 + 0.7*dB + 0.5*dmx + 0.3*dmn;\n}\n\n// Enumerate partitions of n with parts in [ms..maxPart], nonincreasing\nstatic void enum_partitions(int n, int maxPart, int ms, vector<int>& cur,\n                            unordered_set<string>& seen, vector<Part>& pool, int limit){\n    if ((int)pool.size() >= limit) return;\n    if (n == 0) {\n        string k = key_of(cur);\n        if (seen.insert(k).second) pool.push_back(make_part(cur));\n        return;\n    }\n    int up = min(maxPart, n);\n    for (int x = up; x >= ms; --x) {\n        cur.push_back(x);\n        enum_partitions(n - x, x, ms, cur, seen, pool, limit);\n        cur.pop_back();\n        if ((int)pool.size() >= limit) return;\n    }\n}\n\nstatic void add_deterministic_parts(int N, int ms, unordered_set<string>& seen, vector<Part>& pool, int limit){\n    auto add = [&](vector<int> v){\n        if ((int)pool.size() >= limit) return;\n        for (int &x: v) if (x < ms) return;\n        sort(v.begin(), v.end(), greater<int>());\n        if (accumulate(v.begin(), v.end(), 0) != N) return;\n        string k = key_of(v);\n        if (seen.insert(k).second) pool.push_back(make_part(v));\n    };\n\n    // Single clique\n    add({N});\n\n    // Two cliques: N-a, a\n    for(int a=ms; a<=min(N-ms, ms+20); a++){\n        add({N-a, a});\n    }\n\n    // Balanced-ish for B=3..10\n    for(int B=3; B<=10; B++){\n        if (B*ms > N) break;\n        int rem = N - B*ms;\n        int q = rem / B, r = rem % B;\n        vector<int> v(B, ms+q);\n        for(int i=0;i<r;i++) v[i]++;\n        add(v);\n\n        // staircase skew\n        v.assign(B, ms);\n        for(int i=0;i<B && rem>0;i++){\n            int take = min(rem, i+1);\n            v[i] += take;\n            rem -= take;\n        }\n        add(v);\n    }\n}\n\nstatic void random_partitions(int N, int ms, double eps, SplitMix64& rng,\n                              unordered_set<string>& seen, vector<Part>& pool, int limit){\n    int Bmax;\n    if (eps <= 0.10) Bmax = 20;\n    else if (eps <= 0.20) Bmax = 14;\n    else if (eps <= 0.30) Bmax = 10;\n    else if (eps <= 0.35) Bmax = 8;\n    else Bmax = 7;\n    Bmax = min(Bmax, N / ms);\n    int Bmin = 1;\n    if (Bmax <= 0) return;\n\n    int tries = 0;\n    int maxTries = limit * 60; // stronger than before (still fine)\n    while ((int)pool.size() < limit && tries < maxTries) {\n        tries++;\n        int B = rng.next_int(Bmin, Bmax);\n        if (B * ms > N) continue;\n\n        int rem = N - B * ms;\n        vector<int> cuts;\n        cuts.reserve(B+1);\n        cuts.push_back(0);\n        for (int i=0;i<B-1;i++) cuts.push_back(rng.next_int(0, rem));\n        cuts.push_back(rem);\n        sort(cuts.begin(), cuts.end());\n        vector<int> add(B);\n        for (int i=0;i<B;i++) add[i] = cuts[i+1] - cuts[i];\n\n        vector<int> sz(B);\n        for (int i=0;i<B;i++) sz[i] = ms + add[i];\n        sort(sz.begin(), sz.end(), greater<int>());\n\n        string k = key_of(sz);\n        if (!seen.insert(k).second) continue;\n        pool.push_back(make_part(sz));\n    }\n}\n\nstatic vector<Part> build_pool(int N, int ms, double eps, int poolTarget, SplitMix64& rng){\n    vector<Part> pool;\n    pool.reserve(poolTarget);\n    unordered_set<string> seen;\n    seen.reserve(poolTarget * 2);\n\n    add_deterministic_parts(N, ms, seen, pool, poolTarget);\n\n    if (N <= 32) {\n        vector<int> cur;\n        enum_partitions(N, N, ms, cur, seen, pool, poolTarget);\n    } else {\n        random_partitions(N, ms, eps, rng, seen, pool, poolTarget);\n    }\n    return pool;\n}\n\nint main(){\n    // Avoid SIGPIPE termination if judge closes pipe due to illegal output (extra safety).\n    signal(SIGPIPE, SIG_IGN);\n\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    int ms = choose_ms(eps);\n\n    uint64_t seed = 0x123456789abcdefULL;\n    seed ^= (uint64_t)M * 1000003ULL;\n    seed ^= (uint64_t)llround(eps * 100000.0) * 10007ULL;\n    SplitMix64 rng(seed);\n\n    int N = chooseN_init(M, eps);\n\n    const int poolTarget = 25000;\n\n    vector<Part> pool;\n    while (true) {\n        pool = build_pool(N, ms, eps, poolTarget, rng);\n        if ((int)pool.size() >= M) break;\n        if (N >= 100) break;\n        N++;\n    }\n\n    int L = N*(N-1)/2;\n    long long totalTri = C3(N);\n\n    // Precompute logP[s][d] for degree distribution given clique size s\n    vector<vector<double>> logP(N+1, vector<double>(N, -1e100));\n    for (int s=1;s<=N;s++){\n        int n1=s-1, n2=N-s;\n        double p1=1.0-eps, p2=eps;\n        auto pmf1=binom_pmf(n1,p1);\n        auto pmf2=binom_pmf(n2,p2);\n        vector<double> conv(N,0.0);\n        for (int a=0;a<=n1;a++){\n            double pa=pmf1[a]; if(pa==0.0) continue;\n            for (int b=0;b<=n2;b++){\n                double pb=pmf2[b]; if(pb==0.0) continue;\n                conv[a+b] += pa*pb;\n            }\n        }\n        for (int d=0;d<=N-1;d++){\n            logP[s][d] = log(max(conv[d], 1e-300));\n        }\n    }\n\n    int P = (int)pool.size();\n    if (P == 0) {\n        // Defensive fallback\n        cout << 4 << \"\\n\";\n        for(int k=0;k<M;k++) cout << string(6,'0') << \"\\n\";\n        cout.flush();\n        for(int q=0;q<100;q++){\n            string H; cin >> H;\n            cout << 0 << \"\\n\";\n            cout.flush();\n        }\n        return 0;\n    }\n\n    // Select M partitions by farthest point sampling in feature space\n    vector<int> chosen;\n    chosen.reserve(M);\n    vector<char> used(P, 0);\n    vector<double> mind(P, 1e100);\n\n    int first = 0;\n    for (int i=1;i<P;i++) if (pool[i].S3 > pool[first].S3) first = i;\n    chosen.push_back(first);\n    used[first] = 1;\n    for (int i=0;i<P;i++) mind[i] = part_dist(pool[i], pool[first], N, L, totalTri);\n\n    while ((int)chosen.size() < M) {\n        int best = -1;\n        double bestVal = -1;\n        for (int i=0;i<P;i++){\n            if (used[i]) continue;\n            if (mind[i] > bestVal) { bestVal = mind[i]; best = i; }\n        }\n        if (best < 0) break;\n        used[best] = 1;\n        chosen.push_back(best);\n        for (int i=0;i<P;i++){\n            if (used[i]) continue;\n            double d = part_dist(pool[i], pool[best], N, L, totalTri);\n            if (d < mind[i]) mind[i] = d;\n        }\n    }\n    while ((int)chosen.size() < M) chosen.push_back(chosen.back());\n\n    // Build codebook and precompute triangle type counts + expected centered spectrum (top/bottom K)\n    int Kspec = min(12, N);\n    vector<vector<int>> codes(M);\n    vector<int> Eorig(M,0);\n    vector<long long> type1(M,0), type2(M,0), type3(M,0);\n    vector<array<double, 12>> expTop(M), expBot(M); // store up to 12\n\n    double scale = (1.0 - 2.0*eps); // >= 0.2\n    for (int k=0;k<M;k++){\n        const Part& pp = pool[chosen[k]];\n        codes[k] = pp.sz;\n        Eorig[k] = pp.E;\n\n        long long t1=0, t2=0;\n        for (int s: codes[k]) {\n            t1 += C3(s);\n            t2 += C2(s) * (long long)(N - s);\n        }\n        long long t3 = totalTri - t1 - t2;\n        type1[k]=t1; type2[k]=t2; type3[k]=t3;\n\n        // Expected centered eigenvalues of C: scale * eigenvalues(A0)\n        // eigen(A0): (s_i - 1) for each clique, and -1 repeated N - B\n        vector<double> eig;\n        eig.reserve(N);\n        for (int s: codes[k]) eig.push_back(scale * (double)(s - 1));\n        int B = (int)codes[k].size();\n        for (int i=0;i<N-B;i++) eig.push_back(scale * (-1.0));\n        sort(eig.begin(), eig.end()); // ascending\n\n        for(int i=0;i<12;i++){ expTop[k][i]=0; expBot[k][i]=0; }\n        for (int i=0;i<Kspec;i++){\n            expBot[k][i] = eig[i];\n            expTop[k][i] = eig[N-1-i];\n        }\n    }\n\n    // Output graphs: disjoint union of cliques\n    cout << N << \"\\n\";\n    for (int k=0;k<M;k++){\n        const auto& part = codes[k];\n        vector<int> blk(N, -1);\n        int cur = 0;\n        for (int b=0;b<(int)part.size();b++){\n            for (int t=0;t<part[b];t++) blk[cur++] = b;\n        }\n        while (cur < N) blk[cur++] = (int)part.size(); // safety padding (shouldn't happen)\n\n        string g;\n        g.reserve(L);\n        for (int i=0;i<N;i++){\n            for (int j=i+1;j<N;j++){\n                g.push_back(blk[i]==blk[j] ? '1' : '0');\n            }\n        }\n        if ((int)g.size() != L) g.assign(L, '0');\n        cout << g << \"\\n\";\n    }\n    cout.flush();\n\n    // Decoder weights\n    double varE = max(1e-6, (double)L * eps * (1.0 - eps));\n    double wEdge = (eps <= 0.05 ? 0.05 : (eps <= 0.20 ? 0.14 : 0.18));\n    double wTri  = (eps <= 0.10 ? 0.12 : (eps <= 0.25 ? 0.22 : 0.28));\n    double wSpec = (eps <= 0.05 ? 0.60 : (eps <= 0.15 ? 0.45 : (eps <= 0.25 ? 0.32 : 0.26)));\n    double specScaleVar = max(1e-6, (double)N * max(0.01, eps*(1.0-eps)));\n\n    int W = (N + 63) / 64;\n\n    for (int q=0;q<100;q++){\n        string H;\n        if(!(cin >> H)) break;\n\n        vector<int> deg(N, 0);\n        int m = 0;\n\n        vector<vector<uint64_t>> adj(N, vector<uint64_t>(W, 0ULL));\n        Eigen::MatrixXd C = Eigen::MatrixXd::Zero(N, N); // centered adjacency\n\n        int idx=0;\n        for (int i=0;i<N;i++){\n            for (int j=i+1;j<N;j++){\n                char c = H[idx++];\n                if (c=='1'){\n                    deg[i]++; deg[j]++; m++;\n                    adj[i][j>>6] |= 1ULL<<(j&63);\n                    adj[j][i>>6] |= 1ULL<<(i&63);\n                    double v = 1.0 - eps;\n                    C(i,j) = v; C(j,i) = v;\n                } else {\n                    double v = -eps;\n                    C(i,j) = v; C(j,i) = v;\n                }\n            }\n        }\n\n        // triangles\n        long long tri3 = 0;\n        for (int i=0;i<N;i++){\n            for (int j=i+1;j<N;j++){\n                if ((adj[i][j>>6] >> (j&63)) & 1ULL) {\n                    for (int w=0;w<W;w++){\n                        tri3 += __builtin_popcountll(adj[i][w] & adj[j][w]);\n                    }\n                }\n            }\n        }\n        long long Tobs = tri3 / 3;\n\n        // spectrum of centered adjacency\n        Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(C, Eigen::EigenvaluesOnly);\n        Eigen::VectorXd eigv = es.eigenvalues(); // ascending\n        array<double, 12> obsTop{}, obsBot{};\n        for(int i=0;i<12;i++){ obsTop[i]=0; obsBot[i]=0; }\n        for (int i=0;i<Kspec;i++){\n            obsBot[i] = eigv[i];\n            obsTop[i] = eigv[N-1-i];\n        }\n\n        sort(deg.begin(), deg.end(), greater<int>());\n\n        int bestK = 0;\n        double bestScore = -1e300;\n\n        for (int k=0;k<M;k++){\n            const auto& part = codes[k];\n\n            // Degree log-likelihood by monotone assignment\n            double sc = 0.0;\n            int pos = 0;\n            for (int s: part){\n                for (int t=0;t<s;t++){\n                    sc += logP[s][deg[pos++]];\n                }\n            }\n\n            // Edge count penalty\n            if (eps > 0.0 && eps < 1.0){\n                double muE = eps*(double)L + (1.0 - 2.0*eps)*(double)Eorig[k];\n                double z = (double)m - muE;\n                sc += wEdge * (-0.5 * (z*z) / varE);\n            }\n\n            // Triangle count penalty (approx)\n            {\n                double e = eps;\n                double p1 = (1.0-e)*(1.0-e)*(1.0-e);\n                double p2 = (1.0-e)*e*e;\n                double p3 = e*e*e;\n\n                double muT = (double)type1[k]*p1 + (double)type2[k]*p2 + (double)type3[k]*p3;\n                double varT =\n                    (double)type1[k]*p1*(1.0-p1) +\n                    (double)type2[k]*p2*(1.0-p2) +\n                    (double)type3[k]*p3*(1.0-p3);\n                varT = max(varT, 1e-6);\n\n                double z = (double)Tobs - muT;\n                sc += wTri * (-0.5 * (z*z) / varT);\n            }\n\n            // Spectral penalty (top+bottom K)\n            {\n                double diff = 0.0;\n                for (int i=0;i<Kspec;i++){\n                    double d1 = obsTop[i] - expTop[k][i];\n                    double d2 = obsBot[i] - expBot[k][i];\n                    diff += d1*d1 + d2*d2;\n                }\n                sc += wSpec * (-0.5 * diff / specScaleVar);\n            }\n\n            if (sc > bestScore){\n                bestScore = sc;\n                bestK = k;\n            }\n        }\n\n        cout << bestK << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstatic inline long long comb2(long long c) { return c * (c - 1) / 2; }\nstatic inline long double pow4(long double x) { long double s = x * x; return s * s; }\n\n// Morton key for 0..2047 (11 bits)\nstatic inline uint64_t morton11(uint32_t x, uint32_t y) {\n    uint64_t key = 0;\n    for (int b = 0; b < 11; b++) {\n        key |= (uint64_t)((x >> b) & 1u) << (2 * b);\n        key |= (uint64_t)((y >> b) & 1u) << (2 * b + 1);\n    }\n    return key;\n}\n\nstruct Edge {\n    int u, v;\n    long long w;\n    uint64_t key;\n    int prefDay;\n    long double imp; // scaled to [0,1]\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, D, K;\n    cin >> N >> M >> D >> K;\n\n    vector<Edge> edges(M);\n    vector<long long> W(M);\n    vector<vector<pair<int,int>>> g(N); // (to, edgeId)\n\n    for (int i = 0; i < M; i++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i].u = u; edges[i].v = v; edges[i].w = w;\n        W[i] = w;\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    vector<int> X(N), Y(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n    vector<int> deg(N);\n    for (int v = 0; v < N; v++) deg[v] = (int)g[v].size();\n\n    // ---- DFS spanning tree + LCA for partial 2-edge-cut detection ----\n    vector<int> parent(N, -1), parentEdge(N, -1), depth(N, 0);\n    vector<int> tin(N, -1), tout(N, -1), order;\n    vector<char> vis(N, 0), isTreeEdge(M, 0);\n    int timer = 0;\n\n    function<void(int)> dfs = [&](int v) {\n        vis[v] = 1;\n        tin[v] = timer++;\n        order.push_back(v);\n        for (auto [to, eid] : g[v]) {\n            if (to == parent[v]) continue;\n            if (!vis[to]) {\n                parent[to] = v;\n                parentEdge[to] = eid;\n                depth[to] = depth[v] + 1;\n                isTreeEdge[eid] = 1;\n                dfs(to);\n            }\n        }\n        tout[v] = timer++;\n    };\n    dfs(0);\n\n    int LOG = 1;\n    while ((1 << LOG) <= N) LOG++;\n    vector<vector<int>> up(LOG, vector<int>(N, -1));\n    for (int i = 0; i < N; i++) up[0][i] = parent[i];\n    for (int k = 1; k < LOG; k++) {\n        for (int i = 0; i < N; i++) {\n            int p = up[k-1][i];\n            up[k][i] = (p == -1 ? -1 : up[k-1][p]);\n        }\n    }\n\n    auto is_ancestor = [&](int a, int b) -> bool {\n        return tin[a] <= tin[b] && tout[b] <= tout[a];\n    };\n    auto lca = [&](int a, int b) -> int {\n        if (is_ancestor(a, b)) return a;\n        if (is_ancestor(b, a)) return b;\n        int v = a;\n        for (int k = LOG - 1; k >= 0; k--) {\n            int p = up[k][v];\n            if (p != -1 && !is_ancestor(p, b)) v = p;\n        }\n        return parent[v];\n    };\n\n    // ---- Detect many 2-edge-cuts of size 2: (tree edge, unique crossing non-tree edge) ----\n    vector<long long> cntDelta(N, 0), cntSub(N, 0);\n    vector<int> xorDelta(N, 0), xorSub(N, 0);\n\n    for (int eid = 0; eid < M; eid++) {\n        if (isTreeEdge[eid]) continue;\n        int u = edges[eid].u, v = edges[eid].v;\n        int L = lca(u, v);\n        cntDelta[u] += 1;\n        cntDelta[v] += 1;\n        cntDelta[L] -= 2;\n        xorDelta[u] ^= eid;\n        xorDelta[v] ^= eid;\n    }\n\n    for (int i = 0; i < N; i++) { cntSub[i] = cntDelta[i]; xorSub[i] = xorDelta[i]; }\n    for (int idx = (int)order.size() - 1; idx >= 1; idx--) {\n        int v = order[idx];\n        int p = parent[v];\n        cntSub[p] += cntSub[v];\n        xorSub[p] ^= xorSub[v];\n    }\n\n    vector<vector<int>> conflict(M);\n    vector<pair<int,int>> conflictPairs;\n    for (int v = 1; v < N; v++) {\n        if (cntSub[v] == 1) {\n            int eTree = parentEdge[v];\n            int eNonTree = xorSub[v];\n            if (eTree >= 0 && eNonTree >= 0 && eTree != eNonTree) {\n                conflict[eTree].push_back(eNonTree);\n                conflict[eNonTree].push_back(eTree);\n                int a = min(eTree, eNonTree), b = max(eTree, eNonTree);\n                conflictPairs.push_back({a, b});\n            }\n        }\n    }\n    for (int i = 0; i < M; i++) {\n        auto &c = conflict[i];\n        sort(c.begin(), c.end());\n        c.erase(unique(c.begin(), c.end()), c.end());\n    }\n    sort(conflictPairs.begin(), conflictPairs.end());\n    conflictPairs.erase(unique(conflictPairs.begin(), conflictPairs.end()), conflictPairs.end());\n\n    // ---- Importance: sampled Brandes edge-betweenness (weighted) ----\n    // choose sources by farthest point sampling in coordinate space\n    int S = min(70, N);\n    vector<int> sources;\n    sources.reserve(S);\n    vector<long long> bestDist2(N, (1LL<<62));\n    sources.push_back(0);\n    bestDist2[0] = 0;\n    for (int it = 1; it < S; it++) {\n        int last = sources.back();\n        for (int v = 0; v < N; v++) {\n            long long dx = X[v] - X[last];\n            long long dy = Y[v] - Y[last];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 < bestDist2[v]) bestDist2[v] = d2;\n        }\n        int farV = 0;\n        for (int v = 1; v < N; v++) if (bestDist2[v] > bestDist2[farV]) farV = v;\n        sources.push_back(farV);\n    }\n\n    long double meanW = 0;\n    for (auto &e : edges) meanW += (long double)e.w;\n    meanW /= max(1, M);\n\n    vector<long double> rawImp(M, 0.0L);\n    const long long INF = (1LL<<62);\n    vector<long long> dist(N);\n    vector<long double> sigma(N), delta(N);\n    vector<vector<pair<int,int>>> preds(N); // (predVertex, edgeId)\n    vector<int> Sorder; Sorder.reserve(N);\n\n    for (int s : sources) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(sigma.begin(), sigma.end(), 0.0L);\n        for (int i = 0; i < N; i++) preds[i].clear();\n        Sorder.clear();\n\n        dist[s] = 0;\n        sigma[s] = 1.0L;\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dist[v]) continue;\n            Sorder.push_back(v);\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    pq.push({nd, to});\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back({v, eid});\n                } else if (nd == dist[to]) {\n                    sigma[to] += sigma[v];\n                    preds[to].push_back({v, eid});\n                }\n            }\n        }\n\n        fill(delta.begin(), delta.end(), 0.0L);\n        for (int idx = (int)Sorder.size() - 1; idx >= 0; idx--) {\n            int wv = Sorder[idx];\n            long double sw = sigma[wv];\n            if (sw == 0) continue;\n            for (auto [pv, eid] : preds[wv]) {\n                long double c = (sigma[pv] / sw) * (1.0L + delta[wv]);\n                delta[pv] += c;\n                // weight edges slightly by length (optional, mild)\n                long double factor = 1.0L + (long double)W[eid] / meanW;\n                rawImp[eid] += c * factor;\n            }\n        }\n    }\n\n    long double maxRaw = 1e-18L;\n    for (int i = 0; i < M; i++) maxRaw = max(maxRaw, rawImp[i]);\n    for (int i = 0; i < M; i++) edges[i].imp = rawImp[i] / maxRaw;\n\n    // ---- Spatial prefDay by Morton order of edge midpoint ----\n    vector<int> idxKey(M);\n    iota(idxKey.begin(), idxKey.end(), 0);\n    for (int i = 0; i < M; i++) {\n        uint32_t mx = (uint32_t)(X[edges[i].u] + X[edges[i].v]);\n        uint32_t my = (uint32_t)(Y[edges[i].u] + Y[edges[i].v]);\n        edges[i].key = morton11(mx, my);\n    }\n    sort(idxKey.begin(), idxKey.end(), [&](int a, int b){ return edges[a].key < edges[b].key; });\n\n    int base = M / D, rem = M % D;\n    vector<int> desiredSize(D, base);\n    for (int d = 0; d < rem; d++) desiredSize[d]++;\n\n    {\n        int curp = 0;\n        for (int d = 0; d < D; d++) {\n            for (int t = 0; t < desiredSize[d]; t++) {\n                int eid = idxKey[curp++];\n                edges[eid].prefDay = d;\n            }\n        }\n    }\n\n    // ---- Greedy initial assignment: importance-desc, near prefDay, respecting constraints ----\n    vector<int> dayOfEdge(M, -1);\n    vector<vector<int>> inDay(D);\n    vector<int> posInDay(M, -1);\n    vector<vector<int>> inc(D, vector<int>(N, 0)); // removed-incident counts\n\n    vector<int> idxImp(M);\n    iota(idxImp.begin(), idxImp.end(), 0);\n    sort(idxImp.begin(), idxImp.end(), [&](int a, int b){\n        return edges[a].imp > edges[b].imp;\n    });\n\n    vector<long double> sumImp(D, 0.0L);\n\n    auto canPlace = [&](int e, int d) -> bool {\n        if ((int)inDay[d].size() >= K) return false;\n        for (int p : conflict[e]) {\n            int pd = dayOfEdge[p];\n            if (pd == d) return false;\n        }\n        int u = edges[e].u, v = edges[e].v;\n        if (inc[d][u] + 1 > deg[u] - 1) return false; // anti-isolation hard\n        if (inc[d][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    auto assignTo = [&](int e, int d) {\n        dayOfEdge[e] = d;\n        posInDay[e] = (int)inDay[d].size();\n        inDay[d].push_back(e);\n        inc[d][edges[e].u]++; inc[d][edges[e].v]++;\n        sumImp[d] += edges[e].imp;\n    };\n\n    for (int e : idxImp) {\n        int pd = edges[e].prefDay;\n        int bestD = -1;\n        long double bestScore = 1e100L;\n\n        for (int r = 0; r < D && bestD == -1; r++) {\n            int d1 = pd - r;\n            int d2 = pd + r;\n            if (d1 >= 0) {\n                if (canPlace(e, d1)) {\n                    long double score = sumImp[d1] + 0.002L * (long double)inDay[d1].size();\n                    if (score < bestScore) bestScore = score, bestD = d1;\n                }\n            }\n            if (d2 < D && d2 != d1) {\n                if (canPlace(e, d2)) {\n                    long double score = sumImp[d2] + 0.002L * (long double)inDay[d2].size();\n                    if (score < bestScore) bestScore = score, bestD = d2;\n                }\n            }\n        }\n        if (bestD == -1) {\n            // fallback (should be rare)\n            for (int d = 0; d < D; d++) if (canPlace(e, d)) { bestD = d; break; }\n        }\n        if (bestD == -1) {\n            // absolute fallback: ignore anti-isolation (still shouldn't happen)\n            for (int d = 0; d < D; d++) {\n                if ((int)inDay[d].size() < K) { bestD = d; break; }\n            }\n        }\n        assignTo(e, bestD);\n    }\n\n    // ---- helper: move edge (lists + inc + sumImp) ----\n    auto applyMoveOnlyLists = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        int p = posInDay[e];\n        int last = inDay[od].back();\n        inDay[od][p] = last;\n        posInDay[last] = p;\n        inDay[od].pop_back();\n        posInDay[e] = (int)inDay[nd].size();\n        inDay[nd].push_back(e);\n        dayOfEdge[e] = nd;\n    };\n    auto doMoveUpdateIncSum = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        int u = edges[e].u, v = edges[e].v;\n        inc[od][u]--; inc[od][v]--;\n        inc[nd][u]++; inc[nd][v]++;\n        sumImp[od] -= edges[e].imp;\n        sumImp[nd] += edges[e].imp;\n        applyMoveOnlyLists(e, nd);\n    };\n\n    // ---- Fix remaining detected conflicts greedily (should be few) ----\n    auto canPlaceNoConflictDay = [&](int e, int d) -> bool {\n        for (int p : conflict[e]) if (dayOfEdge[p] == d) return false;\n        return true;\n    };\n    auto vertexOkTo = [&](int e, int nd) -> bool {\n        int u = edges[e].u, v = edges[e].v;\n        return (inc[nd][u] + 1 <= deg[u] - 1) && (inc[nd][v] + 1 <= deg[v] - 1);\n    };\n\n    for (auto [a, b] : conflictPairs) {\n        if (dayOfEdge[a] != dayOfEdge[b]) continue;\n        int bad = dayOfEdge[a];\n        bool fixed = false;\n        for (int nd = 0; nd < D && !fixed; nd++) {\n            if (nd == bad) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(b, nd)) continue;\n            if (!vertexOkTo(b, nd)) continue;\n            doMoveUpdateIncSum(b, nd);\n            fixed = true;\n        }\n        for (int nd = 0; nd < D && !fixed; nd++) {\n            if (nd == bad) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(a, nd)) continue;\n            if (!vertexOkTo(a, nd)) continue;\n            doMoveUpdateIncSum(a, nd);\n            fixed = true;\n        }\n    }\n\n    // ---- Post: repair isolation violations (should be none, but safety) ----\n    auto fixIsolationOnce = [&]() -> bool {\n        for (int d = 0; d < D; d++) {\n            for (int v = 0; v < N; v++) {\n                if (inc[d][v] == deg[v]) {\n                    int bestE = -1;\n                    long double bestImp = 1e100L;\n                    for (auto [to, eid] : g[v]) {\n                        (void)to;\n                        if (dayOfEdge[eid] != d) continue;\n                        if (edges[eid].imp < bestImp) bestImp = edges[eid].imp, bestE = eid;\n                    }\n                    if (bestE == -1) continue;\n                    for (int nd = 0; nd < D; nd++) {\n                        if (nd == d) continue;\n                        if ((int)inDay[nd].size() >= K) continue;\n                        if (!canPlaceNoConflictDay(bestE, nd)) continue;\n                        if (!vertexOkTo(bestE, nd)) continue;\n                        doMoveUpdateIncSum(bestE, nd);\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    };\n    for (int rep = 0; rep < 3000; rep++) if (!fixIsolationOnce()) break;\n\n    // ---- SA stats ----\n    // Cost = A*sum pow4(sumImp[d]) + PV*sum_{d,v} C(inc[d][v],2) + SZ*sum (size-desired)^2 + B*misCount\n    const long double A = 1.0L;\n    const long double PV = 4.0L;\n    const long double SZ = 0.25L;\n    const long double B = 0.005L;\n\n    vector<long long> dayPairs(D, 0);\n    long double sumImp4 = 0;\n    long double sizeCost = 0;\n    long long misCount = 0;\n\n    auto recomputeAll = [&]() {\n        sumImp4 = 0;\n        for (int d = 0; d < D; d++) sumImp4 += pow4(sumImp[d]);\n\n        for (int d = 0; d < D; d++) {\n            long long pairs = 0;\n            for (int v = 0; v < N; v++) pairs += comb2(inc[d][v]);\n            dayPairs[d] = pairs;\n        }\n        sizeCost = 0;\n        for (int d = 0; d < D; d++) {\n            long double diff = (long double)inDay[d].size() - (long double)desiredSize[d];\n            sizeCost += diff * diff;\n        }\n        misCount = 0;\n        for (int e = 0; e < M; e++) if (dayOfEdge[e] != edges[e].prefDay) misCount++;\n    };\n    recomputeAll();\n\n    auto computeCost = [&]() -> long double {\n        long double p = 0;\n        for (int d = 0; d < D; d++) p += (long double)dayPairs[d];\n        return A * sumImp4 + PV * p + SZ * sizeCost + B * (long double)misCount;\n    };\n    long double curCost = computeCost();\n\n    auto hardCheckMove = [&](int e, int nd) -> bool {\n        int od = dayOfEdge[e];\n        if (od == nd) return false;\n        if ((int)inDay[nd].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == nd) return false;\n        int u = edges[e].u, v = edges[e].v;\n        if (inc[nd][u] + 1 > deg[u] - 1) return false;\n        if (inc[nd][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    auto hardCheckSwap = [&](int e1, int e2, int d1, int d2) -> bool {\n        if (d1 == d2) return false;\n        auto newDay = [&](int e)->int {\n            if (e == e1) return d2;\n            if (e == e2) return d1;\n            return dayOfEdge[e];\n        };\n        for (int p : conflict[e1]) if (newDay(p) == d2) return false;\n        for (int p : conflict[e2]) if (newDay(p) == d1) return false;\n\n        vector<int> vs = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs.begin(), vs.end());\n        vs.erase(unique(vs.begin(), vs.end()), vs.end());\n\n        for (int v : vs) {\n            int c1 = inc[d1][v];\n            int c2 = inc[d2][v];\n            if (edges[e1].u == v) { c1--; c2++; }\n            if (edges[e1].v == v) { c1--; c2++; }\n            if (edges[e2].u == v) { c2--; c1++; }\n            if (edges[e2].v == v) { c2--; c1++; }\n            if (c1 > deg[v] - 1) return false;\n            if (c2 > deg[v] - 1) return false;\n        }\n        return true;\n    };\n\n    auto applyMoveWithStats = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n\n        // sumImp4 delta\n        long double a0 = sumImp[od], b0 = sumImp[nd];\n        long double imp = edges[e].imp;\n        long double a1 = a0 - imp, b1 = b0 + imp;\n        long double deltaImp4 = pow4(a1) + pow4(b1) - pow4(a0) - pow4(b0);\n\n        // sizeCost delta\n        long double so0 = (long double)inDay[od].size();\n        long double sn0 = (long double)inDay[nd].size();\n        long double dso = so0 - (long double)desiredSize[od];\n        long double dsn = sn0 - (long double)desiredSize[nd];\n        long double dso1 = (so0 - 1.0L) - (long double)desiredSize[od];\n        long double dsn1 = (sn0 + 1.0L) - (long double)desiredSize[nd];\n        long double deltaSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n        // mis delta\n        long long oldMis = (od != edges[e].prefDay);\n        long long newMis = (nd != edges[e].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // dayPairs delta (two vertices, two days)\n        int u = edges[e].u, v = edges[e].v;\n        long long deltaPairs = 0;\n        auto updOne = [&](int day, int vert, int dc) {\n            int oldc = inc[day][vert];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        };\n        updOne(od, u, -1); updOne(od, v, -1);\n        updOne(nd, u, +1); updOne(nd, v, +1);\n\n        curCost += A * deltaImp4 + PV * (long double)deltaPairs + SZ * deltaSize + B * (long double)deltaMis;\n\n        sumImp4 += deltaImp4;\n        sizeCost += deltaSize;\n        misCount += deltaMis;\n\n        // apply dayPairs/inc\n        auto applyIncPairs = [&](int day, int vert, int dc) {\n            dayPairs[day] -= comb2(inc[day][vert]);\n            inc[day][vert] += dc;\n            dayPairs[day] += comb2(inc[day][vert]);\n        };\n        applyIncPairs(od, u, -1); applyIncPairs(od, v, -1);\n        applyIncPairs(nd, u, +1); applyIncPairs(nd, v, +1);\n\n        // apply sums & lists\n        sumImp[od] = a1;\n        sumImp[nd] = b1;\n        doMoveUpdateIncSum(e, nd); // already updates inc/sumImp/lists, but we already did inc/sumImp above -> avoid double\n        // fix: we must not double-apply. So we must apply lists only here.\n        // We'll undo the accidental call: implement directly below instead.\n    };\n\n    // The above attempt would double-apply; implement correct versions:\n    // We'll redefine applyMoveWithStats and applySwapWithStats cleanly using applyMoveOnlyLists only.\n\n    // Reset to a consistent state then re-define properly:\n    recomputeAll();\n    curCost = computeCost();\n\n    auto applyMoveWithStats2 = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n\n        // sumImp4 delta\n        long double a0 = sumImp[od], b0 = sumImp[nd];\n        long double imp = edges[e].imp;\n        long double a1 = a0 - imp, b1 = b0 + imp;\n        long double deltaImp4 = pow4(a1) + pow4(b1) - pow4(a0) - pow4(b0);\n\n        // sizeCost delta\n        long double so0 = (long double)inDay[od].size();\n        long double sn0 = (long double)inDay[nd].size();\n        long double dso = so0 - (long double)desiredSize[od];\n        long double dsn = sn0 - (long double)desiredSize[nd];\n        long double dso1 = (so0 - 1.0L) - (long double)desiredSize[od];\n        long double dsn1 = (sn0 + 1.0L) - (long double)desiredSize[nd];\n        long double deltaSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n        // mis delta\n        long long oldMis = (od != edges[e].prefDay);\n        long long newMis = (nd != edges[e].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // dayPairs delta\n        int u = edges[e].u, v = edges[e].v;\n        long long deltaPairs = 0;\n        auto updOne = [&](int day, int vert, int dc) {\n            int oldc = inc[day][vert];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        };\n        updOne(od, u, -1); updOne(od, v, -1);\n        updOne(nd, u, +1); updOne(nd, v, +1);\n\n        curCost += A * deltaImp4 + PV * (long double)deltaPairs + SZ * deltaSize + B * (long double)deltaMis;\n\n        // apply aggregates\n        sumImp4 += deltaImp4;\n        sizeCost += deltaSize;\n        misCount += deltaMis;\n        sumImp[od] = a1;\n        sumImp[nd] = b1;\n\n        // apply dayPairs/inc\n        auto applyIncPairs = [&](int day, int vert, int dc) {\n            dayPairs[day] -= comb2(inc[day][vert]);\n            inc[day][vert] += dc;\n            dayPairs[day] += comb2(inc[day][vert]);\n        };\n        applyIncPairs(od, u, -1); applyIncPairs(od, v, -1);\n        applyIncPairs(nd, u, +1); applyIncPairs(nd, v, +1);\n\n        // move in lists\n        applyMoveOnlyLists(e, nd);\n    };\n\n    auto applySwapWithStats = [&](int e1, int e2) {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        if (d1 == d2) return;\n\n        // sumImp4 delta\n        long double s1 = sumImp[d1], s2 = sumImp[d2];\n        long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n        long double ns1 = s1 - i1 + i2;\n        long double ns2 = s2 - i2 + i1;\n        long double deltaImp4 = pow4(ns1) + pow4(ns2) - pow4(s1) - pow4(s2);\n\n        // mis delta\n        long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n        long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        // dayPairs delta via merged mods\n        struct Mod { int day, v, dc; };\n        array<Mod,8> mods = {{\n            {d1, edges[e1].u, -1}, {d1, edges[e1].v, -1},\n            {d2, edges[e1].u, +1}, {d2, edges[e1].v, +1},\n            {d2, edges[e2].u, -1}, {d2, edges[e2].v, -1},\n            {d1, edges[e2].u, +1}, {d1, edges[e2].v, +1},\n        }};\n        long long deltaPairs = 0;\n        for (int i = 0; i < 8; i++) {\n            int day = mods[i].day, v = mods[i].v;\n            int dc = mods[i].dc;\n            if (dc == 0) continue;\n            for (int j = i+1; j < 8; j++) {\n                if (mods[j].day == day && mods[j].v == v) {\n                    dc += mods[j].dc;\n                    mods[j].dc = 0;\n                }\n            }\n            int oldc = inc[day][v];\n            int newc = oldc + dc;\n            deltaPairs += (comb2(newc) - comb2(oldc));\n        }\n\n        // sizeCost unchanged on swap\n\n        curCost += A * deltaImp4 + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp4 += deltaImp4;\n        misCount += deltaMis;\n        sumImp[d1] = ns1;\n        sumImp[d2] = ns2;\n\n        auto applyIncPairs = [&](int day, int vert, int dc) {\n            dayPairs[day] -= comb2(inc[day][vert]);\n            inc[day][vert] += dc;\n            dayPairs[day] += comb2(inc[day][vert]);\n        };\n\n        applyIncPairs(d1, edges[e1].u, -1); applyIncPairs(d1, edges[e1].v, -1);\n        applyIncPairs(d2, edges[e1].u, +1); applyIncPairs(d2, edges[e1].v, +1);\n        applyIncPairs(d2, edges[e2].u, -1); applyIncPairs(d2, edges[e2].v, -1);\n        applyIncPairs(d1, edges[e2].u, +1); applyIncPairs(d1, edges[e2].v, +1);\n\n        applyMoveOnlyLists(e1, d2);\n        applyMoveOnlyLists(e2, d1);\n    };\n\n    // ---- Simulated annealing ----\n    XorShift64 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    const double TIME_LIMIT = 5.55;\n\n    int iters = 0;\n    while (true) {\n        iters++;\n        if ((iters & 2047) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed > TIME_LIMIT) break;\n        }\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = elapsed / TIME_LIMIT;\n        double T = 3.5 * (1.0 - t) + 0.05 * t;\n\n        int op = rng.nextInt(100);\n        if (op < 72) {\n            int e1 = rng.nextInt(M);\n            int e2 = rng.nextInt(M);\n            if (e1 == e2) continue;\n            int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n            if (d1 == d2) continue;\n            if (!hardCheckSwap(e1, e2, d1, d2)) continue;\n\n            long double oldC = curCost;\n\n            // compute delta quickly similarly to applySwapWithStats (duplicate minimal)\n            long double s1 = sumImp[d1], s2 = sumImp[d2];\n            long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n            long double ns1 = s1 - i1 + i2;\n            long double ns2 = s2 - i2 + i1;\n            long double deltaImp4 = pow4(ns1) + pow4(ns2) - pow4(s1) - pow4(s2);\n\n            long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n            long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            struct Mod { int day, v, dc; };\n            array<Mod,8> mods = {{\n                {d1, edges[e1].u, -1}, {d1, edges[e1].v, -1},\n                {d2, edges[e1].u, +1}, {d2, edges[e1].v, +1},\n                {d2, edges[e2].u, -1}, {d2, edges[e2].v, -1},\n                {d1, edges[e2].u, +1}, {d1, edges[e2].v, +1},\n            }};\n            long long deltaPairs = 0;\n            for (int i = 0; i < 8; i++) {\n                int day = mods[i].day, v = mods[i].v;\n                int dc = mods[i].dc;\n                if (dc == 0) continue;\n                for (int j = i+1; j < 8; j++) {\n                    if (mods[j].day == day && mods[j].v == v) {\n                        dc += mods[j].dc;\n                        mods[j].dc = 0;\n                    }\n                }\n                int oldc = inc[day][v];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            }\n\n            long double delta = A * deltaImp4 + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else if (rng.nextDouble() < exp(-(double)delta / T)) accept = true;\n\n            if (accept) applySwapWithStats(e1, e2);\n            else curCost = oldC;\n\n        } else {\n            int e = rng.nextInt(M);\n            int nd = rng.nextInt(D);\n            if (!hardCheckMove(e, nd)) continue;\n\n            long double oldC = curCost;\n\n            int od = dayOfEdge[e];\n            long double a0 = sumImp[od], b0 = sumImp[nd];\n            long double imp = edges[e].imp;\n            long double a1 = a0 - imp, b1 = b0 + imp;\n            long double deltaImp4 = pow4(a1) + pow4(b1) - pow4(a0) - pow4(b0);\n\n            long double so0 = (long double)inDay[od].size();\n            long double sn0 = (long double)inDay[nd].size();\n            long double dso = so0 - (long double)desiredSize[od];\n            long double dsn = sn0 - (long double)desiredSize[nd];\n            long double dso1 = (so0 - 1.0L) - (long double)desiredSize[od];\n            long double dsn1 = (sn0 + 1.0L) - (long double)desiredSize[nd];\n            long double deltaSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n            long long oldMis = (od != edges[e].prefDay);\n            long long newMis = (nd != edges[e].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            int u = edges[e].u, v = edges[e].v;\n            long long deltaPairs = 0;\n            auto updOne = [&](int day, int vert, int dc) {\n                int oldc = inc[day][vert];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            };\n            updOne(od, u, -1); updOne(od, v, -1);\n            updOne(nd, u, +1); updOne(nd, v, +1);\n\n            long double delta = A * deltaImp4 + PV * (long double)deltaPairs + SZ * deltaSize + B * (long double)deltaMis;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else if (rng.nextDouble() < exp(-(double)delta / T)) accept = true;\n\n            if (accept) applyMoveWithStats2(e, nd);\n            else curCost = oldC;\n        }\n    }\n\n    // ---- Postprocess: fix isolation again (SA should keep it, but safety) ----\n    for (int rep = 0; rep < 2000; rep++) if (!fixIsolationOnce()) break;\n\n    // ---- Connectivity repair (eliminate any remaining disconnect days) ----\n    vector<int> comp(N, -1);\n    auto compCountForDay = [&](int d) -> int {\n        fill(comp.begin(), comp.end(), -1);\n        int cid = 0;\n        deque<int> q;\n        for (int s = 0; s < N; s++) {\n            if (comp[s] != -1) continue;\n            comp[s] = cid++;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                for (auto [to, eid] : g[v]) {\n                    if (dayOfEdge[eid] == d) continue; // closed\n                    if (comp[to] != -1) continue;\n                    comp[to] = comp[v];\n                    q.push_back(to);\n                }\n            }\n        }\n        return cid;\n    };\n\n    auto tryMoveEdgeToSomeDay = [&](int e, int fromDay) -> bool {\n        int u = edges[e].u, v = edges[e].v;\n        // choose days with smallest load first\n        vector<int> days(D);\n        iota(days.begin(), days.end(), 0);\n        sort(days.begin(), days.end(), [&](int a, int b){ return inDay[a].size() < inDay[b].size(); });\n        for (int nd : days) {\n            if (nd == fromDay) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(e, nd)) continue;\n            if (inc[nd][u] + 1 > deg[u] - 1) continue;\n            if (inc[nd][v] + 1 > deg[v] - 1) continue;\n            // do move\n            inc[fromDay][u]--; inc[fromDay][v]--;\n            inc[nd][u]++; inc[nd][v]++;\n            applyMoveOnlyLists(e, nd);\n            return true;\n        }\n        return false;\n    };\n\n    int moveBudget = 2500;\n    while (moveBudget-- > 0) {\n        bool anyDisconnected = false;\n        for (int d = 0; d < D; d++) {\n            int cc = compCountForDay(d);\n            if (cc <= 1) continue;\n            anyDisconnected = true;\n\n            vector<int> cand;\n            cand.reserve(inDay[d].size());\n            for (int e : inDay[d]) {\n                if (comp[edges[e].u] != comp[edges[e].v]) cand.push_back(e);\n            }\n            if (cand.empty()) {\n                // fallback: move least-importance edge\n                int bestE = -1;\n                long double bestI = 1e100L;\n                for (int e : inDay[d]) if (edges[e].imp < bestI) bestI = edges[e].imp, bestE = e;\n                if (bestE != -1) tryMoveEdgeToSomeDay(bestE, d);\n                break;\n            }\n            sort(cand.begin(), cand.end(), [&](int a, int b){ return edges[a].imp < edges[b].imp; });\n            for (int e : cand) {\n                if (tryMoveEdgeToSomeDay(e, d)) break;\n            }\n            break; // re-evaluate after one move\n        }\n        if (!anyDisconnected) break;\n    }\n\n    // final isolation cleanup (connectivity moves can create it)\n    for (int rep = 0; rep < 2000; rep++) if (!fixIsolationOnce()) break;\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (dayOfEdge[i] + 1);\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed=88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n    double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Segment {\n    int x, y, z;\n    int axis; // 0:x 1:y 2:z\n    int len;\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstatic long long volume_of(const vector<uint8_t>& occ) {\n    long long v = 0;\n    for (auto c : occ) v += (c != 0);\n    return v;\n}\n\n// ---- silhouette constructions ----\n\n// DP to choose stable representative per z (maximize staying same between adjacent z).\nstatic vector<int> choose_stable_sequence(const vector<vector<int>>& opts) {\n    int D = (int)opts.size();\n    vector<vector<int>> par(D);\n    vector<long long> dp_prev, dp_cur;\n\n    dp_prev.assign(opts[0].size(), 0);\n    par[0].assign(opts[0].size(), -1);\n\n    for (int z = 1; z < D; z++) {\n        dp_cur.assign(opts[z].size(), LLONG_MIN / 4);\n        par[z].assign(opts[z].size(), -1);\n        for (int j = 0; j < (int)opts[z].size(); j++) {\n            for (int p = 0; p < (int)opts[z - 1].size(); p++) {\n                long long cand = dp_prev[p] + (opts[z][j] == opts[z - 1][p] ? 1 : 0);\n                if (cand > dp_cur[j]) {\n                    dp_cur[j] = cand;\n                    par[z][j] = p;\n                }\n            }\n        }\n        dp_prev.swap(dp_cur);\n    }\n\n    int bestj = 0;\n    for (int j = 1; j < (int)dp_prev.size(); j++) if (dp_prev[j] > dp_prev[bestj]) bestj = j;\n\n    vector<int> seq(D);\n    int cur = bestj;\n    for (int z = D - 1; z >= 0; z--) {\n        seq[z] = opts[z][cur];\n        cur = par[z][cur];\n        if (z == 0) break;\n    }\n    return seq;\n}\n\nstatic int choose_global_hub(const vector<vector<int>>& opts, int D) {\n    vector<int> freq(D, 0);\n    for (int z = 0; z < (int)opts.size(); z++) for (int v : opts[z]) freq[v]++;\n    int best = 0;\n    for (int i = 1; i < D; i++) if (freq[i] > freq[best]) best = i;\n    return best;\n}\n\n// type:\n// 0 dense AND\n// 1 star per slice with stable hubs\n// 2 min edge-cover per slice\n// 3 star per slice with global hubs\n// 4 continuity-biased edge-cover (repeat (x,y) between slices)\nstatic vector<uint8_t> build_occ(int D,\n                                 const vector<string>& f,\n                                 const vector<string>& r,\n                                 int type) {\n    vector<vector<int>> X(D), Y(D);\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) if (f[z][x] == '1') X[z].push_back(x);\n        for (int y = 0; y < D; y++) if (r[z][y] == '1') Y[z].push_back(y);\n    }\n\n    vector<uint8_t> occ(D * D * D, 0);\n\n    if (type == 0) {\n        for (int z = 0; z < D; z++)\n            for (int x : X[z])\n                for (int y : Y[z])\n                    occ[idx3(D, x, y, z)] = 1;\n        return occ;\n    }\n\n    if (type == 1) {\n        vector<int> x0 = choose_stable_sequence(X);\n        vector<int> y0 = choose_stable_sequence(Y);\n        for (int z = 0; z < D; z++) {\n            for (int x : X[z]) occ[idx3(D, x, y0[z], z)] = 1;\n            for (int y : Y[z]) occ[idx3(D, x0[z], y, z)] = 1;\n        }\n        return occ;\n    }\n\n    if (type == 2) {\n        for (int z = 0; z < D; z++) {\n            auto &xs = X[z], &ys = Y[z];\n            int nx = (int)xs.size(), ny = (int)ys.size();\n            if (nx >= ny) {\n                for (int j = 0; j < ny; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = ny; j < nx; j++) occ[idx3(D, xs[j], ys[0], z)] = 1;\n            } else {\n                for (int j = 0; j < nx; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n                for (int j = nx; j < ny; j++) occ[idx3(D, xs[0], ys[j], z)] = 1;\n            }\n        }\n        return occ;\n    }\n\n    if (type == 3) {\n        int gx = choose_global_hub(X, D);\n        int gy = choose_global_hub(Y, D);\n        for (int z = 0; z < D; z++) {\n            int xhub = gx, yhub = gy;\n            if (find(X[z].begin(), X[z].end(), xhub) == X[z].end()) xhub = X[z][0];\n            if (find(Y[z].begin(), Y[z].end(), yhub) == Y[z].end()) yhub = Y[z][0];\n            for (int x : X[z]) occ[idx3(D, x, yhub, z)] = 1;\n            for (int y : Y[z]) occ[idx3(D, xhub, y, z)] = 1;\n        }\n        return occ;\n    }\n\n    // type == 4 : continuity-biased edge-cover\n    // Weight[x][y] = number of z where (x,y) is allowed.\n    vector<vector<int>> W(D, vector<int>(D, 0));\n    for (int z = 0; z < D; z++) {\n        for (int x : X[z]) for (int y : Y[z]) W[x][y]++;\n    }\n\n    vector<vector<uint8_t>> prevEdge(D, vector<uint8_t>(D, 0));\n    const int BONUS = 1000; // strong preference to reuse same (x,y)\n\n    for (int z = 0; z < D; z++) {\n        auto &xs = X[z], &ys = Y[z];\n        int nx = (int)xs.size(), ny = (int)ys.size();\n        vector<uint8_t> coveredY(D, 0), coveredX(D, 0);\n        vector<pair<int,int>> edges;\n\n        if (nx >= ny) {\n            // For each x, choose best y.\n            for (int x : xs) {\n                int besty = ys[0];\n                int bests = -1;\n                for (int y : ys) {\n                    int s = W[x][y] + (prevEdge[x][y] ? BONUS : 0);\n                    if (s > bests) { bests = s; besty = y; }\n                }\n                edges.push_back({x, besty});\n                coveredY[besty] = 1;\n                coveredX[x] = 1;\n            }\n            // Ensure all y covered.\n            for (int y : ys) if (!coveredY[y]) {\n                int bestx = xs[0];\n                int bests = -1;\n                for (int x : xs) {\n                    int s = W[x][y] + (prevEdge[x][y] ? BONUS : 0);\n                    if (s > bests) { bests = s; bestx = x; }\n                }\n                edges.push_back({bestx, y});\n            }\n        } else {\n            // For each y, choose best x.\n            for (int y : ys) {\n                int bestx = xs[0];\n                int bests = -1;\n                for (int x : xs) {\n                    int s = W[x][y] + (prevEdge[x][y] ? BONUS : 0);\n                    if (s > bests) { bests = s; bestx = x; }\n                }\n                edges.push_back({bestx, y});\n                coveredX[bestx] = 1;\n                coveredY[y] = 1;\n            }\n            // Ensure all x covered.\n            for (int x : xs) if (!coveredX[x]) {\n                int besty = ys[0];\n                int bests = -1;\n                for (int y : ys) {\n                    int s = W[x][y] + (prevEdge[x][y] ? BONUS : 0);\n                    if (s > bests) { bests = s; besty = y; }\n                }\n                edges.push_back({x, besty});\n            }\n        }\n\n        // Apply edges\n        vector<vector<uint8_t>> curEdge(D, vector<uint8_t>(D, 0));\n        for (auto [x,y] : edges) {\n            occ[idx3(D, x, y, z)] = 1;\n            curEdge[x][y] = 1;\n        }\n        prevEdge.swap(curEdge);\n    }\n\n    return occ;\n}\n\n// ---- stick partitioning and packing ----\n\nstatic int max_run_len_any_axis(int D, const vector<uint8_t>& occ) {\n    int best = 0;\n    // x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !occ[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && occ[idx3(D,x,y,z)]) x++;\n            best = max(best, x-s);\n        }\n    }\n    // y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !occ[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && occ[idx3(D,x,y,z)]) y++;\n            best = max(best, y-s);\n        }\n    }\n    // z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !occ[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && occ[idx3(D,x,y,z)]) z++;\n            best = max(best, z-s);\n        }\n    }\n    return best;\n}\n\n// Find all maximum-length segments in rem (over all axes).\nstatic void find_max_segments(int D, const vector<uint8_t>& rem, int &maxLen, vector<Segment>& bestSegs) {\n    maxLen = 0;\n    bestSegs.clear();\n\n    auto consider = [&](int x,int y,int z,int axis,int len){\n        if (len <= 0) return;\n        if (len > maxLen) { maxLen = len; bestSegs.clear(); }\n        if (len == maxLen) bestSegs.push_back(Segment{x,y,z,axis,len});\n    };\n\n    // axis x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !rem[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && rem[idx3(D,x,y,z)]) x++;\n            consider(s,y,z,0,x-s);\n        }\n    }\n    // axis y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !rem[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && rem[idx3(D,x,y,z)]) y++;\n            consider(x,s,z,1,y-s);\n        }\n    }\n    // axis z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !rem[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && rem[idx3(D,x,y,z)]) z++;\n            consider(x,y,s,2,z-s);\n        }\n    }\n}\n\nstatic void remove_segment_voxels(int D, vector<uint8_t>& rem, const Segment& sg) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1;\n    else if (sg.axis==1) dy=1;\n    else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x = sg.x + dx*t;\n        int y = sg.y + dy*t;\n        int z = sg.z + dz*t;\n        rem[idx3(D,x,y,z)] = 0;\n    }\n}\n\n// Partition occ into sticks using repeated \"take a maximum-length segment\".\n// axisBias influences tie-breaking between axes when many max segments exist.\nstatic vector<Segment> partition_into_sticks(int D, const vector<uint8_t>& occ, array<int,3> axisBias, XorShift& rng) {\n    vector<uint8_t> rem = occ;\n    vector<Segment> res;\n    res.reserve((int)volume_of(occ));\n\n    while (true) {\n        bool any = false;\n        for (auto v: rem) if (v) { any=true; break; }\n        if (!any) break;\n\n        int maxLen;\n        vector<Segment> best;\n        find_max_segments(D, rem, maxLen, best);\n        if (maxLen <= 0 || best.empty()) break;\n\n        // weighted random by axis bias\n        long long tot = 0;\n        for (auto &s: best) tot += axisBias[s.axis];\n        long long r = (long long)(rng.next_u64() % (uint64_t)tot);\n        int pick = 0;\n        for (int i=0;i<(int)best.size();i++) {\n            r -= axisBias[best[i].axis];\n            if (r < 0) { pick = i; break; }\n        }\n        Segment chosen = best[pick];\n        res.push_back(chosen);\n        remove_segment_voxels(D, rem, chosen);\n    }\n    return res;\n}\n\n// Find a best (minimal excess) segment in rem with length >= L, across all axes.\n// Returns true and sets out segment with out.len=L if found.\nstatic bool find_best_segment_for_length(int D, const vector<uint8_t>& rem, int L, XorShift& rng, Segment& out) {\n    int bestEx = INT_MAX;\n    vector<Segment> cand;\n\n    auto consider = [&](int x,int y,int z,int axis,int len){\n        if (len < L) return;\n        int ex = len - L;\n        if (ex < bestEx) { bestEx = ex; cand.clear(); }\n        if (ex == bestEx) cand.push_back(Segment{x,y,z,axis,L});\n    };\n\n    // x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !rem[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && rem[idx3(D,x,y,z)]) x++;\n            consider(s,y,z,0,x-s);\n        }\n    }\n    // y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !rem[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && rem[idx3(D,x,y,z)]) y++;\n            consider(x,s,z,1,y-s);\n        }\n    }\n    // z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !rem[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && rem[idx3(D,x,y,z)]) z++;\n            consider(x,y,s,2,z-s);\n        }\n    }\n\n    if (cand.empty()) return false;\n    out = cand[rng.next_int((int)cand.size())];\n    return true;\n}\n\nstatic void fill_segment_id(int D, vector<int>& b, const Segment& sg, int id) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1;\n    else if (sg.axis==1) dy=1;\n    else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x = sg.x + dx*t;\n        int y = sg.y + dy*t;\n        int z = sg.z + dz*t;\n        b[idx3(D,x,y,z)] = id;\n    }\n}\n\n// Attempt to place all sticks \"need\" into occLarge (voxel-level), producing placements same size.\n// Greedy in descending length with best-fit segment selection.\nstatic bool pack_sticks_into_large(int D,\n                                  const vector<uint8_t>& occLarge,\n                                  const vector<Segment>& need,\n                                  XorShift& rng,\n                                  vector<Segment>& placed,\n                                  int& failLen) {\n    vector<uint8_t> rem = occLarge;\n    int m = (int)need.size();\n    placed.assign(m, Segment{0,0,0,0,0});\n\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int i,int j){\n        if (need[i].len != need[j].len) return need[i].len > need[j].len;\n        return i < j;\n    });\n\n    for (int idx : ord) {\n        int L = need[idx].len;\n        Segment best;\n        if (!find_best_segment_for_length(D, rem, L, rng, best)) {\n            failLen = L;\n            return false;\n        }\n        placed[idx] = best;\n        remove_segment_voxels(D, rem, best);\n    }\n    failLen = 0;\n    return true;\n}\n\nstatic long double penalty_sum_inv(const vector<Segment>& sticks) {\n    long double s = 0.0L;\n    for (auto &sg : sticks) s += 1.0L / (long double)sg.len;\n    return s;\n}\n\n// Split one stick of target length (or the maximum if not found) into two smaller sticks along same axis.\nstatic bool split_one_stick(vector<Segment>& sticks, int targetLen, int cap) {\n    int pos = -1;\n    for (int i=0;i<(int)sticks.size();i++) {\n        if (sticks[i].len == targetLen && sticks[i].len >= 2) { pos = i; break; }\n    }\n    if (pos == -1) {\n        int best = -1;\n        for (int i=0;i<(int)sticks.size();i++) {\n            if (sticks[i].len >= 2 && (best==-1 || sticks[i].len > sticks[best].len)) best = i;\n        }\n        pos = best;\n    }\n    if (pos == -1) return false;\n\n    int L = sticks[pos].len;\n    if (L < 2) return false;\n\n    // Choose a split that tends to keep both parts <= cap if possible, otherwise reduce the oversized part.\n    int a = max(1, L/2);\n    a = min(a, cap);\n    int b = L - a;\n    if (b > cap) {\n        a = cap;\n        b = L - a;\n        if (a < 1 || b < 1) {\n            // fallback\n            a = L-1; b = 1;\n        }\n    }\n    if (a < 1 || b < 1) return false;\n\n    Segment orig = sticks[pos];\n    Segment s1 = orig; s1.len = a;\n    Segment s2 = orig; s2.len = b;\n    if (orig.axis == 0) s2.x += a;\n    else if (orig.axis == 1) s2.y += a;\n    else s2.z += a;\n\n    sticks[pos] = s1;\n    sticks.push_back(s2);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n    vector<string> f[2], r[2];\n    for (int i = 0; i < 2; i++) {\n        f[i].resize(D);\n        r[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> f[i][z];\n        for (int z = 0; z < D; z++) cin >> r[i][z];\n    }\n\n    auto t_start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n    const double TIME_LIMIT = 5.8; // leave margin\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)(uintptr_t)(&D);\n    XorShift rng(seed);\n\n    const int S = 5;\n    vector<uint8_t> occ[2][S];\n    long long vol[2][S];\n    int maxRun[2][S];\n\n    for (int i = 0; i < 2; i++) {\n        for (int s = 0; s < S; s++) {\n            occ[i][s] = build_occ(D, f[i], r[i], s);\n            vol[i][s] = volume_of(occ[i][s]);\n            maxRun[i][s] = max_run_len_any_axis(D, occ[i][s]);\n        }\n    }\n\n    struct BestPlan {\n        long double cost = 1e100L;\n        int s0=-1, s1=-1;\n        int smallObj=-1;\n        vector<Segment> sharedSmall;\n        vector<Segment> sharedLarge;\n    } best;\n\n    // enumerate combos sorted by volume difference (helps find good plan earlier)\n    vector<pair<int,int>> combos;\n    for (int s0=0;s0<S;s0++) for (int s1=0;s1<S;s1++) combos.push_back({s0,s1});\n    sort(combos.begin(), combos.end(), [&](auto a, auto b){\n        long long da = llabs(vol[0][a.first] - vol[1][a.second]);\n        long long db = llabs(vol[0][b.first] - vol[1][b.second]);\n        return da < db;\n    });\n\n    for (auto [s0, s1] : combos) {\n        if (elapsed() > TIME_LIMIT) break;\n\n        // try both directions if possible\n        for (int smallObj : {0,1}) {\n            int largeObj = 1 - smallObj;\n            long long vSmall = (smallObj==0 ? vol[0][s0] : vol[1][s1]);\n            long long vLarge = (largeObj==0 ? vol[0][s0] : vol[1][s1]);\n            if (vSmall > vLarge) continue;\n\n            long double diff = (long double)(vLarge - vSmall);\n            if (diff > best.cost) continue; // very rough prune\n\n            const auto& occSmall = (smallObj==0 ? occ[0][s0] : occ[1][s1]);\n            const auto& occLarge = (largeObj==0 ? occ[0][s0] : occ[1][s1]);\n            int cap = maxRun[largeObj][(largeObj==0? s0:s1)];\n            cap = max(1, cap);\n\n            // number of trials: adaptive to time\n            int trials = 0;\n            int maxTrials = 30;\n            while (trials < maxTrials && elapsed() <= TIME_LIMIT) {\n                trials++;\n\n                // random axis bias (tie-breaker). Favor z sometimes.\n                array<int,3> bias = {1,1,1};\n                int mode = rng.next_int(6);\n                if (mode==0) bias = {3,1,1};\n                else if (mode==1) bias = {1,3,1};\n                else if (mode==2) bias = {1,1,3};\n                else if (mode==3) bias = {2,1,2};\n                else if (mode==4) bias = {2,2,1};\n                else bias = {1,2,2};\n\n                vector<Segment> sticks = partition_into_sticks(D, occSmall, bias, rng);\n\n                // Feasibility via actual placement into large, with splitting if needed.\n                vector<Segment> placed;\n                int failLen = 0;\n                int splitCnt = 0;\n                bool ok = false;\n\n                // Try packing; if fail, split and retry.\n                for (;;) {\n                    if (elapsed() > TIME_LIMIT) break;\n                    XorShift local_rng(rng.next_u64());\n                    if (pack_sticks_into_large(D, occLarge, sticks, local_rng, placed, failLen)) {\n                        ok = true;\n                        break;\n                    }\n                    if (failLen <= 1) { ok = false; break; }\n                    if (!split_one_stick(sticks, failLen, cap)) { ok = false; break; }\n                    splitCnt++;\n                    if (splitCnt > 2000) { ok = false; break; }\n                }\n                if (!ok) continue;\n\n                long double pen = penalty_sum_inv(sticks);\n                long double cost = diff + pen;\n                if (cost < best.cost) {\n                    best.cost = cost;\n                    best.s0 = s0;\n                    best.s1 = s1;\n                    best.smallObj = smallObj;\n                    best.sharedSmall = sticks;\n                    best.sharedLarge = placed;\n                }\n            }\n        }\n    }\n\n    // Fallback (should not happen): if no plan found, use dense and unit cubes.\n    if (best.smallObj == -1) {\n        int s0 = 0, s1 = 0;\n        vector<int> b0(D*D*D,0), b1(D*D*D,0);\n        int n=0;\n        for (int i=0;i<2;i++) {\n            auto &F = f[i];\n            auto &R = r[i];\n            for (int x=0;x<D;x++) for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n                if (F[z][x]=='1' && R[z][y]=='1') {\n                    n++;\n                    if (i==0) b0[idx3(D,x,y,z)] = n;\n                    else b1[idx3(D,x,y,z)] = n;\n                }\n            }\n        }\n        cout << n << \"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b0[i]; } cout<<\"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b1[i]; } cout<<\"\\n\";\n        return 0;\n    }\n\n    int s0 = best.s0, s1 = best.s1;\n    int smallObj = best.smallObj;\n    int largeObj = 1 - smallObj;\n\n    const auto& occ0 = occ[0][s0];\n    const auto& occ1 = occ[1][s1];\n\n    const auto& occSmall = (smallObj==0 ? occ0 : occ1);\n    const auto& occLarge = (largeObj==0 ? occ0 : occ1);\n\n    // Recompute leftover voxels in large after placing shared blocks, then partition leftovers into unique sticks.\n    vector<uint8_t> remLarge = occLarge;\n    for (auto &sg : best.sharedLarge) remove_segment_voxels(D, remLarge, sg);\n\n    // Partition leftovers into any sticks (bias doesn't matter much).\n    array<int,3> ubias = {1,1,1};\n    XorShift rng2(rng.next_u64());\n    vector<Segment> uniqueLarge = partition_into_sticks(D, remLarge, ubias, rng2);\n\n    int m = (int)best.sharedSmall.size();\n    int u = (int)uniqueLarge.size();\n    int n = m + u;\n\n    vector<int> bA(D*D*D, 0), bB(D*D*D, 0); // object0, object1\n\n    int curId = 1;\n    // shared blocks\n    for (int i=0;i<m;i++,curId++) {\n        if (smallObj == 0) {\n            fill_segment_id(D, bA, best.sharedSmall[i], curId);\n            fill_segment_id(D, bB, best.sharedLarge[i], curId);\n        } else {\n            fill_segment_id(D, bB, best.sharedSmall[i], curId);\n            fill_segment_id(D, bA, best.sharedLarge[i], curId);\n        }\n    }\n    // unique blocks in large\n    for (int i=0;i<u;i++,curId++) {\n        if (largeObj == 0) fill_segment_id(D, bA, uniqueLarge[i], curId);\n        else fill_segment_id(D, bB, uniqueLarge[i], curId);\n    }\n\n    cout << n << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << bA[i]; }\n    cout << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << bB[i]; }\n    cout << \"\\n\";\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstatic inline int ceil_sqrt_ll(long long x) {\n    if (x <= 0) return 0;\n    long long r = (long long)floor(sqrt((long double)x));\n    while (r * r < x) ++r;\n    while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n    return (int)r;\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool merge(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// xorshift64 RNG\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Connector {\n    int N, M;\n    vector<Edge> edges;\n    vector<vector<tuple<int,long long,int>>> g; // to, w, edgeId\n\n    vector<vector<long long>> dist;\n    vector<vector<int>> prevV, prevE;\n\n    vector<int> usedStamp;\n    int stamp = 1;\n\n    vector<int> remStamp;\n    int remCurStamp = 1;\n\n    Connector(int N_, int M_, const vector<Edge>& e): N(N_), M(M_), edges(e),\n        g(N), dist(N, vector<long long>(N, (1LL<<62))),\n        prevV(N, vector<int>(N, -1)), prevE(N, vector<int>(N, -1)),\n        usedStamp(M, 0), remStamp(M, 0) {\n\n        for (int i = 0; i < M; i++) {\n            g[edges[i].u].push_back({edges[i].v, edges[i].w, i});\n            g[edges[i].v].push_back({edges[i].u, edges[i].w, i});\n        }\n        all_pairs_dijkstra();\n    }\n\n    void all_pairs_dijkstra() {\n        for (int s = 0; s < N; s++) {\n            auto &ds = dist[s];\n            auto &pv = prevV[s];\n            auto &pe = prevE[s];\n            fill(ds.begin(), ds.end(), (1LL<<62));\n            fill(pv.begin(), pv.end(), -1);\n            fill(pe.begin(), pe.end(), -1);\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            ds[s] = 0; pv[s] = s; pe[s] = -1;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [dcur, v] = pq.top(); pq.pop();\n                if (dcur != ds[v]) continue;\n                for (auto [to, w, id] : g[v]) {\n                    long long nd = dcur + w;\n                    if (nd < ds[to]) {\n                        ds[to] = nd;\n                        pv[to] = v;\n                        pe[to] = id;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n        }\n    }\n\n    // Candidate edges from metric MST expansion\n    vector<int> candidate_metric_mst(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n\n        if ((int)terminals.size() <= 1) return marked;\n\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1; long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i]; v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) { key[u] = d; parent[u] = v; }\n            }\n        }\n\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        // ensure terminal reachability from 0 if something is missing\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true; dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) { reach[to] = true; dq.push_back(to); }\n            }\n        }\n        for (int t : terminals) if (!reach[t]) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        return marked;\n    }\n\n    // Candidate edges from union of shortest paths from 0\n    vector<int> candidate_root_paths(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n        for (int t : terminals) if (t != 0) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n        return marked;\n    }\n\n    pair<long long, vector<int>> prune_candidate(const vector<int>& cand, const vector<char>& isTerm, bool needEdges) {\n        if (cand.empty()) return {0LL, {}};\n\n        vector<int> candSorted = cand;\n        sort(candSorted.begin(), candSorted.end(),\n             [&](int a, int b){ return edges[a].w < edges[b].w; });\n\n        DSU dsu(N);\n        vector<int> treeEdges; treeEdges.reserve(candSorted.size());\n        for (int eid : candSorted) if (dsu.merge(edges[eid].u, edges[eid].v)) treeEdges.push_back(eid);\n\n        vector<vector<pair<int,int>>> adj(N);\n        vector<int> deg(N, 0);\n        for (int eid : treeEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            adj[u].push_back({v, eid});\n            adj[v].push_back({u, eid});\n            deg[u]++; deg[v]++;\n        }\n\n        int curRemStamp = remCurStamp++;\n        auto isRemoved = [&](int eid)->bool { return remStamp[eid] == curRemStamp; };\n        auto setRemoved = [&](int eid){ remStamp[eid] = curRemStamp; };\n\n        deque<int> q;\n        for (int i = 0; i < N; i++) if (!isTerm[i] && deg[i] == 1) q.push_back(i);\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n            int to = -1, eid = -1;\n            for (auto [nx, id] : adj[v]) if (!isRemoved(id)) { to = nx; eid = id; break; }\n            if (eid == -1) { deg[v] = 0; continue; }\n            setRemoved(eid);\n            deg[v]--; deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        long long cost = 0;\n        vector<int> remain;\n        if (needEdges) remain.reserve(treeEdges.size());\n        for (int eid : treeEdges) if (!isRemoved(eid)) {\n            cost += edges[eid].w;\n            if (needEdges) remain.push_back(eid);\n        }\n        return {cost, remain};\n    }\n\n    // Fast cost used inside SA: metric MST expansion only\n    long long steiner_cost_metric(const vector<int>& terminals) {\n        if (terminals.size() <= 1) return 0;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        auto cand = candidate_metric_mst(terminals);\n        return prune_candidate(cand, isTerm, false).first;\n    }\n\n    // Final build: choose better of metric MST vs root-path union\n    vector<char> steiner_build_best(const vector<int>& terminals) {\n        vector<char> on(M, 0);\n        if (terminals.size() <= 1) return on;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n\n        auto candA = candidate_metric_mst(terminals);\n        auto resA = prune_candidate(candA, isTerm, true);\n\n        auto candB = candidate_root_paths(terminals);\n        auto resB = prune_candidate(candB, isTerm, true);\n\n        const auto& best = (resA.first <= resB.first) ? resA : resB;\n        for (int eid : best.second) on[eid] = 1;\n        return on;\n    }\n};\n\nstruct KeyMask {\n    uint64_t a, b;\n    bool operator==(const KeyMask& o) const { return a==o.a && b==o.b; }\n};\nstruct KeyHash {\n    size_t operator()(const KeyMask& k) const {\n        uint64_t x = k.a * 11995408973635179863ULL ^ (k.b + 0x9e3779b97f4a7c15ULL);\n        x ^= x >> 33; x *= 0xff51afd7ed558ccdULL;\n        x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53ULL;\n        x ^= x >> 33;\n        return (size_t)x;\n    }\n};\n\nstruct SAState {\n    int N, K;\n    const vector<int>* dist2;                // K*N\n    const vector<array<int,100>>* order;     // K\n    Connector* conn;\n    unordered_map<KeyMask, long long, KeyHash>* edgeCache;\n\n    static constexpr int D2_LIMIT = 5000 * 5000;\n\n    vector<char> active;\n    vector<int> owner;\n    vector<int> dOwn;\n\n    vector<int> head;\n    vector<int> rprev, rnext;\n\n    vector<multiset<int>> ms;\n    vector<int> P;\n\n    long long radioCost = 0;\n    long long edgeCost = 0;\n    long long totalCost = 0;\n\n    inline int d2(int k, int i) const { return (*dist2)[k*N + i]; }\n\n    void list_remove(int k) {\n        int s = owner[k];\n        int pv = rprev[k], nx = rnext[k];\n        if (pv != -1) rnext[pv] = nx;\n        else head[s] = nx;\n        if (nx != -1) rprev[nx] = pv;\n        rprev[k] = rnext[k] = -1;\n    }\n    void list_add(int k, int s) {\n        int h = head[s];\n        head[s] = k;\n        rprev[k] = -1;\n        rnext[k] = h;\n        if (h != -1) rprev[h] = k;\n    }\n\n    vector<int> terminals() const {\n        vector<int> t; t.reserve(N);\n        t.push_back(0);\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) t.push_back(i);\n        return t;\n    }\n\n    KeyMask terminal_mask() const {\n        uint64_t a=0, b=0;\n        // include 0 always\n        a |= 1ULL;\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) {\n            if (i < 64) a |= 1ULL << i;\n            else b |= 1ULL << (i - 64);\n        }\n        return {a,b};\n    }\n\n    long long edge_cost_cached() {\n        KeyMask km = terminal_mask();\n        auto it = edgeCache->find(km);\n        if (it != edgeCache->end()) return it->second;\n        auto terms = terminals();\n        long long c = conn->steiner_cost_metric(terms);\n        (*edgeCache)[km] = c;\n        return c;\n    }\n\n    int nearest_active(int k, int ex) const {\n        for (int idx = 0; idx < N; idx++) {\n            int v = (*order)[k][idx];\n            if (!active[v]) continue;\n            if (v == ex) continue;\n            int dd = d2(k, v);\n            if (dd <= D2_LIMIT) return v;\n        }\n        return -1;\n    }\n\n    void rebuild_from_active_nearest() {\n        active[0] = 1;\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            for (int idx = 0; idx < N; idx++) {\n                int v = (*order)[k][idx];\n                if (active[v]) { chosen = v; break; }\n            }\n            if (chosen < 0) chosen = 0;\n            int dd = d2(k, chosen);\n            owner[k] = chosen;\n            dOwn[k] = dd;\n            list_add(k, chosen);\n            ms[chosen].insert(dd);\n        }\n\n        for (int i = 1; i < N; i++) if (ms[i].empty()) active[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    void rebuild_from_active_owner(const vector<char>& act, const vector<int>& own) {\n        active = act;\n        active[0] = 1;\n\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int s = own[k];\n            if (s < 0 || s >= N || !active[s] || d2(k, s) > D2_LIMIT) {\n                s = nearest_active(k, -1);\n                if (s < 0) s = 0;\n            }\n            owner[k] = s;\n            int dd = d2(k, s);\n            dOwn[k] = dd;\n            list_add(k, s);\n            ms[s].insert(dd);\n        }\n\n        // make sure non-empty are active\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) active[i] = 1;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    struct Log {\n        vector<tuple<int,int,int>> moved; // (resident, oldOwner, oldDist)\n        vector<pair<int,char>> flipped;   // (station, oldActive)\n        vector<pair<int,int>> oldP;       // (station, oldP)\n        vector<pair<int,char>> oldEmpty;  // (station, oldEmpty)\n        vector<int> touched;\n        vector<char> touchedFlag;\n        long long oldRadio, oldEdge, oldTotal;\n        Log(int N=0): touchedFlag(N, 0) {}\n    };\n\n    void touch_station(int s, Log& log) {\n        if (log.touchedFlag[s]) return;\n        log.touchedFlag[s] = 1;\n        log.touched.push_back(s);\n        log.oldP.push_back({s, P[s]});\n        log.oldEmpty.push_back({s, (char)ms[s].empty()});\n    }\n\n    void move_resident(int k, int newS, Log& log) {\n        int oldS = owner[k];\n        if (oldS == newS) return;\n        int oldD = dOwn[k];\n        log.moved.push_back({k, oldS, oldD});\n\n        touch_station(oldS, log);\n        touch_station(newS, log);\n\n        auto it = ms[oldS].find(oldD);\n        if (it != ms[oldS].end()) ms[oldS].erase(it);\n        int nd = d2(k, newS);\n        ms[newS].insert(nd);\n\n        list_remove(k);\n        owner[k] = newS;\n        dOwn[k] = nd;\n        list_add(k, newS);\n    }\n\n    bool apply_remove(int v, Log& log) {\n        if (v == 0 || !active[v]) return false;\n\n        log.flipped.push_back({v, active[v]});\n        active[v] = 0;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n        return true;\n    }\n\n    bool apply_add(int u, Log& log) {\n        if (active[u]) return false;\n        log.flipped.push_back({u, active[u]});\n        active[u] = 1;\n\n        // move residents who prefer u (distance, then index)\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    bool apply_swap(int v, int u, Log& log) {\n        if (v == 0 || !active[v] || active[u]) return false;\n        log.flipped.push_back({v, active[v]}); active[v] = 0;\n        log.flipped.push_back({u, active[u]}); active[u] = 1;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    void finalize(Log& log) {\n        // update radio incrementally\n        radioCost = log.oldRadio;\n        vector<int> oldpArr(N, -1);\n        vector<char> oldEmptyArr(N, 0);\n        for (auto [s, op] : log.oldP) oldpArr[s] = op;\n        for (auto [s, oe] : log.oldEmpty) oldEmptyArr[s] = oe;\n\n        bool terminalChanged = false;\n        for (int s : log.touched) {\n            int oldp = oldpArr[s];\n            int newp = 0;\n            if (!ms[s].empty()) newp = ceil_sqrt_ll(*ms[s].rbegin());\n            if (newp > 5000) newp = 5000;\n            P[s] = newp;\n            radioCost += 1LL*newp*newp - 1LL*oldp*oldp;\n            if ((bool)oldEmptyArr[s] != ms[s].empty()) terminalChanged = true;\n        }\n\n        if (terminalChanged) edgeCost = edge_cost_cached();\n        else edgeCost = log.oldEdge;\n\n        totalCost = radioCost + edgeCost;\n    }\n\n    void undo(Log& log) {\n        for (int i = (int)log.moved.size() - 1; i >= 0; i--) {\n            auto [k, oldS, oldD] = log.moved[i];\n            int curS = owner[k];\n            int curD = dOwn[k];\n\n            auto it = ms[curS].find(curD);\n            if (it != ms[curS].end()) ms[curS].erase(it);\n            ms[oldS].insert(oldD);\n\n            list_remove(k);\n            owner[k] = oldS;\n            dOwn[k] = oldD;\n            list_add(k, oldS);\n        }\n\n        for (int i = (int)log.flipped.size() - 1; i >= 0; i--) {\n            auto [s, oldA] = log.flipped[i];\n            active[s] = oldA;\n        }\n        for (auto [s, op] : log.oldP) P[s] = op;\n\n        radioCost = log.oldRadio;\n        edgeCost  = log.oldEdge;\n        totalCost = log.oldTotal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n    vector<Edge> edges(M);\n    for (int j = 0; j < M; j++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n    }\n\n    vector<int> a(K), b(K);\n    for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n    vector<int> dist2((size_t)K * N);\n    for (int k = 0; k < K; k++) for (int i = 0; i < N; i++) {\n        long long dx = (long long)x[i] - a[k];\n        long long dy = (long long)y[i] - b[k];\n        dist2[k*N + i] = (int)(dx*dx + dy*dy);\n    }\n\n    vector<array<int,100>> order(K);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) order[k][i] = i;\n        sort(order[k].begin(), order[k].end(), [&](int i, int j){\n            int di = dist2[k*N + i];\n            int dj = dist2[k*N + j];\n            if (di != dj) return di < dj;\n            return i < j;\n        });\n    }\n\n    Connector conn(N, M, edges);\n\n    unordered_map<KeyMask, long long, KeyHash> edgeCache;\n    edgeCache.reserve(1 << 14);\n\n    SAState st;\n    st.N = N; st.K = K;\n    st.dist2 = &dist2;\n    st.order = &order;\n    st.conn = &conn;\n    st.edgeCache = &edgeCache;\n\n    st.active.assign(N, 1);\n    st.rebuild_from_active_nearest();\n\n    RNG rng(123456789);\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n    const double TL = 1.90;\n\n    vector<char> bestActive = st.active;\n    vector<int> bestOwner = st.owner;\n    long long bestCost = st.totalCost;\n\n    // SA schedule (similar to the good 79.24M version)\n    const double T0 = 2e9;\n    const double T1 = 2e6;\n\n    while (elapsed() < TL) {\n        double t = elapsed() / TL;\n        double temp = T0 * pow(T1 / T0, t);\n\n        SAState::Log log(N);\n        log.oldRadio = st.radioCost;\n        log.oldEdge  = st.edgeCost;\n        log.oldTotal = st.totalCost;\n\n        double r = rng.nextDouble();\n        bool ok = false;\n\n        if (r < 0.45) { // remove\n            int v = -1;\n            for (int tries = 0; tries < 20; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (st.active[cand] && !st.ms[cand].empty()) { v = cand; break; }\n            }\n            if (v != -1) ok = st.apply_remove(v, log);\n        } else if (r < 0.80) { // add\n            int u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (!st.active[cand]) { u = cand; break; }\n            }\n            if (u != -1) ok = st.apply_add(u, log);\n        } else { // swap\n            int v = -1, u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int candV = rng.nextInt(1, N-1);\n                if (st.active[candV] && !st.ms[candV].empty()) { v = candV; break; }\n            }\n            for (int tries = 0; tries < 30; tries++) {\n                int candU = rng.nextInt(1, N-1);\n                if (!st.active[candU]) { u = candU; break; }\n            }\n            if (v != -1 && u != -1) ok = st.apply_swap(v, u, log);\n        }\n\n        if (!ok) { st.undo(log); continue; }\n\n        st.finalize(log);\n\n        long long delta = st.totalCost - log.oldTotal;\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(-(double)delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (!accept) { st.undo(log); continue; }\n\n        if (st.totalCost < bestCost) {\n            bestCost = st.totalCost;\n            bestActive = st.active;\n            bestOwner = st.owner;\n        }\n    }\n\n    // Restore best snapshot\n    st.rebuild_from_active_owner(bestActive, bestOwner);\n\n    // Small post-processing: try to relocate outlier residents greedily\n    // (short time slice)\n    const double POST_TL = 1.97;\n    while (elapsed() < POST_TL) {\n        int s = rng.nextInt(0, N-1);\n        if (s != 0 && st.ms[s].empty()) continue;\n        // pick farthest resident in station s\n        int bestK = -1;\n        int bestD = -1;\n        for (int k = st.head[s]; k != -1; k = st.rnext[k]) {\n            if (st.dOwn[k] > bestD) { bestD = st.dOwn[k]; bestK = k; }\n        }\n        if (bestK == -1) continue;\n\n        // try a few nearest stations as new owner (including currently inactive)\n        int curOwner = st.owner[bestK];\n        long long base = st.totalCost;\n        int bestT = -1;\n\n        for (int idx = 0; idx < 8; idx++) {\n            int tStation = order[bestK][idx];\n            if (tStation == curOwner) continue;\n            int dd = dist2[bestK*N + tStation];\n            if (dd > SAState::D2_LIMIT) continue;\n\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n\n            if (!st.active[tStation]) { log.flipped.push_back({tStation, st.active[tStation]}); st.active[tStation] = 1; }\n            st.move_resident(bestK, tStation, log);\n            st.finalize(log);\n\n            if (st.totalCost < base) {\n                base = st.totalCost;\n                bestT = tStation;\n            }\n            st.undo(log);\n        }\n\n        if (bestT != -1) {\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n            if (!st.active[bestT]) { log.flipped.push_back({bestT, st.active[bestT]}); st.active[bestT] = 1; }\n            st.move_resident(bestK, bestT, log);\n            st.finalize(log);\n            // keep only if improved\n            if (st.totalCost >= log.oldTotal) st.undo(log);\n        }\n    }\n\n    // Final cable set (best of two constructions, done only once)\n    vector<int> terms = st.terminals();\n    vector<char> on = conn.steiner_build_best(terms);\n\n    // Output P_1..P_N\n    for (int i = 0; i < N; i++) {\n        int pi = st.P[i];\n        if (pi < 0) pi = 0;\n        if (pi > 5000) pi = 5000;\n        cout << pi << (i+1==N?'\\n':' ');\n    }\n    // Output B_1..B_M\n    for (int j = 0; j < M; j++) {\n        cout << (int)on[j] << (j+1==M?'\\n':' ');\n    }\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int M = N * (N + 1) / 2;\nstatic constexpr int LIMIT = 10000;\n\nstatic inline int ID(int x, int y) { return x * (x + 1) / 2 + y; }\n\n// splitmix64 RNG\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// Precompute structure\nstruct Precomp {\n    array<int, M> X{}, Y{};\n    array<array<int,2>, M> par{};\n    array<int, M> parCnt{};\n    array<array<int,2>, M> ch{};\n    array<int, M> chCnt{};\n\n    // downward edges list (parent -> child)\n    int Ecnt = 0;\n    array<int, N*(N-1)> eP{};\n    array<int, N*(N-1)> eC{};\n    array<array<int,4>, M> inc{}; // incident edge ids per node (<=4)\n    array<int, M> incCnt{};\n\n    Precomp() {\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v = ID(x,y);\n                X[v] = x; Y[v] = y;\n\n                parCnt[v] = 0;\n                if (x > 0) {\n                    if (y > 0) par[v][parCnt[v]++] = ID(x-1, y-1);\n                    if (y < x) par[v][parCnt[v]++] = ID(x-1, y);\n                }\n                chCnt[v] = 0;\n                if (x + 1 < N) {\n                    ch[v][chCnt[v]++] = ID(x+1, y);\n                    ch[v][chCnt[v]++] = ID(x+1, y+1);\n                }\n                incCnt[v] = 0;\n            }\n        }\n        // build edges and incident lists\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = ID(x,y);\n                for (int i = 0; i < chCnt[p]; i++) {\n                    int c = ch[p][i];\n                    int eid = Ecnt++;\n                    eP[eid] = p;\n                    eC[eid] = c;\n                    inc[p][incCnt[p]++] = eid;\n                    inc[c][incCnt[c]++] = eid;\n                }\n            }\n        }\n    }\n};\nstatic Precomp PC;\n\nstruct PQEdge {\n    int diff;\n    uint32_t tie;\n    int p, c;\n    bool operator<(PQEdge const& o) const {\n        if (diff != o.diff) return diff < o.diff; // max by diff\n        return tie < o.tie; // max by tie\n    }\n};\n\nstruct Result {\n    int E;\n    int K;\n    vector<pair<int,int>> ops; // store node IDs (u,v)\n};\n\nstruct Runner {\n    array<int, M> a{};\n    int curE = 0;\n\n    priority_queue<PQEdge> pq;\n    vector<pair<int,int>> ops;\n\n    SplitMix64 rng;\n    bool randomized;\n\n    Runner(uint64_t seed, bool randomized_) : rng(seed), randomized(randomized_) {}\n\n    inline bool violated(int eid) const {\n        return a[PC.eP[eid]] > a[PC.eC[eid]];\n    }\n\n    inline void push_edge_if_viol(int p, int c) {\n        if (a[p] > a[c]) {\n            uint32_t tie = randomized ? rng.next_u32() : 0u;\n            pq.push(PQEdge{a[p] - a[c], tie, p, c});\n        }\n    }\n\n    inline void push_incident_edges(int u) {\n        for (int i = 0; i < PC.incCnt[u]; i++) {\n            int eid = PC.inc[u][i];\n            int p = PC.eP[eid], c = PC.eC[eid];\n            push_edge_if_viol(p, c);\n        }\n    }\n\n    bool do_swap_nodes(int u, int v) {\n        // allow swap even at LIMIT if it cancels last op\n        bool can_cancel = !ops.empty() &&\n            ((ops.back().first == u && ops.back().second == v) ||\n             (ops.back().first == v && ops.back().second == u));\n        if ((int)ops.size() >= LIMIT && !can_cancel) return false;\n\n        // collect touched edges (<= 8, dedup manually)\n        int touched[8], tcnt = 0;\n        auto add_eid = [&](int eid) {\n            for (int i = 0; i < tcnt; i++) if (touched[i] == eid) return;\n            touched[tcnt++] = eid;\n        };\n        for (int i = 0; i < PC.incCnt[u]; i++) add_eid(PC.inc[u][i]);\n        for (int i = 0; i < PC.incCnt[v]; i++) add_eid(PC.inc[v][i]);\n\n        // update curE: remove old contributions\n        for (int i = 0; i < tcnt; i++) if (violated(touched[i])) curE--;\n\n        // perform swap in state\n        swap(a[u], a[v]);\n\n        // update curE: add new contributions\n        for (int i = 0; i < tcnt; i++) if (violated(touched[i])) curE++;\n\n        // push potentially new violations\n        for (int i = 0; i < tcnt; i++) {\n            int eid = touched[i];\n            int p = PC.eP[eid], c = PC.eC[eid];\n            push_edge_if_viol(p, c);\n        }\n\n        // online cancellation of consecutive identical swaps\n        if (can_cancel) {\n            ops.pop_back(); // removes previous; current is not recorded\n        } else {\n            ops.push_back({u,v});\n        }\n        return true;\n    }\n\n    void bubble_up(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestP = -1;\n            int bestVal = -1;\n\n            for (int i = 0; i < PC.parCnt[u]; i++) {\n                int p = PC.par[u][i];\n                if (a[p] > a[u]) {\n                    int pv = a[p];\n                    if (pv > bestVal) {\n                        bestVal = pv;\n                        bestP = p;\n                    } else if (pv == bestVal && randomized) {\n                        // random tie-break\n                        if (rng.next_u32() & 1u) bestP = p;\n                    }\n                }\n            }\n            if (bestP == -1) break;\n            if (!do_swap_nodes(bestP, u)) break;\n            u = bestP;\n        }\n    }\n\n    void bubble_down(int u) {\n        while ((int)ops.size() < LIMIT) {\n            int bestC = -1;\n            int bestVal = INT_MAX;\n\n            for (int i = 0; i < PC.chCnt[u]; i++) {\n                int c = PC.ch[u][i];\n                if (a[u] > a[c]) {\n                    int cv = a[c];\n                    if (cv < bestVal) {\n                        bestVal = cv;\n                        bestC = c;\n                    } else if (cv == bestVal && randomized) {\n                        if (rng.next_u32() & 1u) bestC = c;\n                    }\n                }\n            }\n            if (bestC == -1) break;\n            if (!do_swap_nodes(u, bestC)) break;\n            u = bestC;\n        }\n    }\n\n    Result run(const array<int,M>& initA, bool useBubbleDown) {\n        a = initA;\n        ops.clear();\n        while (!pq.empty()) pq.pop();\n\n        // compute initial E and init PQ with all violations\n        curE = 0;\n        for (int eid = 0; eid < PC.Ecnt; eid++) {\n            int p = PC.eP[eid], c = PC.eC[eid];\n            if (a[p] > a[c]) {\n                curE++;\n                push_edge_if_viol(p, c);\n            }\n        }\n\n        while (curE > 0 && (int)ops.size() < LIMIT && !pq.empty()) {\n            auto e = pq.top(); pq.pop();\n            int p = e.p, c = e.c;\n            if (a[p] <= a[c]) continue; // stale\n\n            if (!do_swap_nodes(p, c)) break;\n\n            // After swap: smaller moved to p, larger moved to c\n            bubble_up(p);\n            if (useBubbleDown) bubble_down(c);\n        }\n\n        return Result{curE, (int)ops.size(), ops};\n    }\n};\n\nstatic inline bool better(const Result& A, const Result& B) {\n    // prioritize smaller E; if E==0 prioritize smaller K; otherwise also smaller K (secondary)\n    if (A.E != B.E) return A.E < B.E;\n    return A.K < B.K;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    array<int, M> initA{};\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            int v; cin >> v;\n            initA[ID(x,y)] = v;\n        }\n    }\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n    const double TL = 1.85;\n\n    Result best{INT_MAX, INT_MAX, {}};\n\n    // Attempt 0: deterministic baseline (should be close to your original good result)\n    {\n        Runner r(0, false);\n        auto res = r.run(initA, true);\n        best = res;\n    }\n\n    // Additional attempts: randomized tie-breaking + variant (with/without bubble_down)\n    uint64_t baseSeed =\n        (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    int it = 0;\n    while (elapsed() < TL) {\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)(it + 1);\n\n        {\n            Runner r(seed, true);\n            auto res = r.run(initA, true);\n            if (better(res, best)) best = std::move(res);\n        }\n        if (elapsed() >= TL) break;\n\n        {\n            Runner r(seed ^ 0xD1B54A32D192ED03ULL, true);\n            auto res = r.run(initA, false); // sometimes fewer swaps\n            if (better(res, best)) best = std::move(res);\n        }\n\n        it++;\n    }\n\n    // Output\n    cout << best.ops.size() << \"\\n\";\n    for (auto [u,v] : best.ops) {\n        cout << PC.X[u] << \" \" << PC.Y[u] << \" \" << PC.X[v] << \" \" << PC.Y[v] << \"\\n\";\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    cin >> D >> N;\n\n    const int ei = 0, ej = (D - 1) / 2;\n    auto inside = [&](int i, int j) { return 0 <= i && i < D && 0 <= j && j < D; };\n    auto vid = [&](int i, int j) { return i * D + j; };\n    auto pos = [&](int v) { return pair<int,int>(v / D, v % D); };\n\n    const int V = D * D;\n    const int root = vid(ei, ej);\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    // Storable cells (all free cells except entrance)\n    vector<int> storableCells;\n    storableCells.reserve(V);\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == ei && j == ej) continue;\n        if (obstacle[i][j]) continue;\n        storableCells.push_back(vid(i, j));\n    }\n    const int M = (int)storableCells.size(); // = D^2-1-N\n\n    // Map cell -> container index k (0..M-1), or -1\n    vector<int> kOfCell(V, -1);\n    for (int k = 0; k < M; k++) kOfCell[storableCells[k]] = k;\n\n    // Precompute static distance from entrance ignoring containers (only obstacles)\n    const int INF = 1e9;\n    vector<int> dist(V, INF);\n    {\n        queue<int> q;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obstacle[ni][nj]) continue;\n                int u = vid(ni, nj);\n                if (dist[u] > dist[v] + 1) {\n                    dist[u] = dist[v] + 1;\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    // Degree in obstacle-filtered grid\n    vector<int> deg(V, 0);\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) continue;\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obstacle[ni][nj]) continue;\n            c++;\n        }\n        deg[v] = c;\n    }\n\n    // Priority order for mapping small labels to \"easy early\" cells:\n    // close to entrance, higher degree (more accessible), then tie by coordinates.\n    vector<int> priority = storableCells;\n    sort(priority.begin(), priority.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    vector<int> rankv(V, -1);\n    for (int r = 0; r < M; r++) rankv[priority[r]] = r;\n\n    // Placement state\n    vector<char> occupied(V, 0);\n    vector<int> label_at(V, -1);\n\n    auto is_empty_placement = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;\n        return !occupied[v];\n    };\n\n    auto bfs_reachable_empty = [&](vector<char>& vis) -> int {\n        vis.assign(V, 0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n        int cnt = 1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_placement(u)) continue;\n                vis[u] = 1;\n                q.push(u);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    auto count_total_empty = [&]() -> int {\n        int total = 0;\n        for (int v = 0; v < V; v++) {\n            auto [i, j] = pos(v);\n            if (obstacle[i][j]) continue;\n            if (v == root) { total++; continue; }\n            if (!occupied[v]) total++;\n        }\n        return total;\n    };\n\n    auto placement_is_safe = [&](int cell) -> bool {\n        // cell is currently empty storable reachable; test that after occupying it,\n        // all remaining empty cells remain connected to entrance.\n        occupied[cell] = 1;\n        vector<char> vis;\n        int reach = bfs_reachable_empty(vis);\n        int total = count_total_empty();\n        occupied[cell] = 0;\n        return reach == total;\n    };\n\n    // ===== Placement phase (interactive) =====\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<char> vis;\n        bfs_reachable_empty(vis);\n\n        vector<int> candidates;\n        candidates.reserve(M);\n        for (int v : storableCells) {\n            if (occupied[v]) continue;\n            if (!vis[v]) continue; // must be reachable through empty squares\n            candidates.push_back(v);\n        }\n\n        // Score candidates: match label to rank, but must pass safety check.\n        // Try top L by heuristic first, then expand if needed.\n        struct Cand { int v; long long key; };\n        vector<Cand> order;\n        order.reserve(candidates.size());\n        for (int v : candidates) {\n            long long diff = (long long)rankv[v] - t;\n            long long key = diff * diff * 1000LL + dist[v] * 10LL - deg[v]; // heuristic only\n            order.push_back({v, key});\n        }\n        sort(order.begin(), order.end(), [&](const Cand& a, const Cand& b) {\n            if (a.key != b.key) return a.key < b.key;\n            return a.v < b.v;\n        });\n\n        int chosen = -1;\n        int L = min<int>(12, (int)order.size());\n        for (int i = 0; i < L; i++) {\n            int v = order[i].v;\n            if (placement_is_safe(v)) { chosen = v; break; }\n        }\n        if (chosen == -1) {\n            // fallback: brute search any safe candidate (guaranteed to exist)\n            for (auto &c : order) {\n                if (placement_is_safe(c.v)) { chosen = c.v; break; }\n            }\n        }\n        if (chosen == -1) {\n            // ultimate fallback (should never happen): pick first reachable\n            chosen = order[0].v;\n        }\n\n        occupied[chosen] = 1;\n        label_at[chosen] = t;\n        auto [pi, pj] = pos(chosen);\n        cout << pi << ' ' << pj << '\\n';\n        cout.flush();\n    }\n\n    // ===== Shipping phase =====\n    vector<int> labelOf(M);\n    for (int k = 0; k < M; k++) labelOf[k] = label_at[storableCells[k]];\n\n    // removedMask bit k => container removed (cell becomes empty)\n    unsigned __int128 removedMask = 0;\n\n    auto is_empty_ship = [&](int cell, unsigned __int128 mask) -> bool {\n        auto [i, j] = pos(cell);\n        if (obstacle[i][j]) return false;\n        if (cell == root) return true;\n        int k = kOfCell[cell];\n        if (k < 0) return false;\n        return ((mask >> k) & 1) != 0;\n    };\n\n    auto compute_boundary = [&](unsigned __int128 mask, vector<int>& boundary, int& reachEmpty) {\n        static array<char, 81> vis;\n        vis.fill(0);\n        array<int, 81> q;\n        int qh = 0, qt = 0;\n\n        vis[root] = 1;\n        q[qt++] = root;\n        while (qh < qt) {\n            int v = q[qh++];\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_ship(u, mask)) continue;\n                vis[u] = 1;\n                q[qt++] = u;\n            }\n        }\n        reachEmpty = qt;\n\n        static array<char, 80> seen; // M<=80\n        seen.fill(0);\n        boundary.clear();\n\n        for (int qi = 0; qi < qt; qi++) {\n            int v = q[qi];\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                int k = kOfCell[u];\n                if (k < 0) continue;\n                if (((mask >> k) & 1) != 0) continue; // already removed\n                if (!seen[k]) {\n                    seen[k] = 1;\n                    boundary.push_back(k);\n                }\n            }\n        }\n    };\n\n    auto min_boundary_labels_after = [&](unsigned __int128 mask, int& m1, int& m2, int& reachEmpty) {\n        vector<int> boundary;\n        compute_boundary(mask, boundary, reachEmpty);\n        m1 = M + 5; m2 = M + 5;\n        for (int k : boundary) {\n            int lab = labelOf[k];\n            if (lab < m1) { m2 = m1; m1 = lab; }\n            else if (lab < m2) { m2 = lab; }\n        }\n    };\n\n    for (int step = 0; step < M; step++) {\n        vector<int> boundary;\n        int reachEmpty = 0;\n        compute_boundary(removedMask, boundary, reachEmpty);\n\n        // boundary should always be non-empty until finished\n        if (boundary.empty()) {\n            // fallback (shouldn't happen): remove any remaining\n            for (int k = 0; k < M; k++) {\n                if (((removedMask >> k) & 1) == 0) { boundary.push_back(k); break; }\n            }\n        }\n\n        // Candidate set: few smallest labels + a few that may unlock (by distance/degree)\n        vector<int> byLabel = boundary;\n        sort(byLabel.begin(), byLabel.end(), [&](int a, int b) {\n            if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n            return a < b;\n        });\n        if ((int)byLabel.size() > 12) byLabel.resize(12);\n\n        vector<int> byUnlock = boundary;\n        sort(byUnlock.begin(), byUnlock.end(), [&](int a, int b) {\n            int ca = storableCells[a], cb = storableCells[b];\n            // prefer removing \"near entrance / high degree\" blockers\n            if (dist[ca] != dist[cb]) return dist[ca] < dist[cb];\n            if (deg[ca] != deg[cb]) return deg[ca] > deg[cb];\n            return a < b;\n        });\n        if ((int)byUnlock.size() > 6) byUnlock.resize(6);\n\n        vector<int> cand = byLabel;\n        cand.insert(cand.end(), byUnlock.begin(), byUnlock.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int bestK = cand[0];\n        long long bestScore = (1LL<<62);\n\n        for (int k : cand) {\n            unsigned __int128 newMask = removedMask | ((unsigned __int128)1 << k);\n\n            int m1, m2, reach2;\n            min_boundary_labels_after(newMask, m1, m2, reach2);\n\n            long long lab = labelOf[k];\n            // primary: keep sequence close to increasing => small label early\n            // secondary: unlock smaller labels soon (m1,m2), and grow reachable empty area\n            long long score = lab * 1000000LL + m1 * 5000LL + m2 * 500LL - reach2 * 5LL;\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestK = k;\n            }\n        }\n\n        removedMask |= (unsigned __int128)1 << bestK;\n        int cell = storableCells[bestK];\n        auto [qi, qj] = pos(cell);\n        cout << qi << ' ' << qj << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int DX[4] = {1, -1, 0, 0};\nstatic constexpr int DY[4] = {0, 0, 1, -1};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> orig(n, vector<int>(n));\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> orig[i][j];\n\n    const int C = m + 1; // 0..m\n\n    auto inside = [&](int i, int j) { return (0 <= i && i < n && 0 <= j && j < n); };\n    auto is_boundary = [&](int i, int j) { return (i == 0 || i == n - 1 || j == 0 || j == n - 1); };\n    auto idx = [&](int i, int j) { return i * n + j; };\n\n    // Required adjacency matrix (existence)\n    vector<vector<char>> req(C, vector<char>(C, 0));\n    vector<char> req0(C, 0);\n\n    // From original grid: adjacencies between colors\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = orig[i][j];\n            if (i + 1 < n) {\n                int b = orig[i + 1][j];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n            if (j + 1 < n) {\n                int b = orig[i][j + 1];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n        }\n    }\n    // Outside adjacency (0): boundary cells touch outside\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (!is_boundary(i, j)) continue;\n            int c = orig[i][j];\n            req[0][c] = req[c][0] = 1;\n            req0[c] = 1;\n        }\n    }\n\n    auto coastal = [&](int c) -> bool { return c > 0 && req0[c]; };\n\n    // Graph distance to coastal set (on color adjacency graph excluding 0)\n    vector<vector<int>> adj(m + 1);\n    for (int u = 1; u <= m; u++) {\n        for (int v = 1; v <= m; v++) if (req[u][v]) adj[u].push_back(v);\n    }\n    const int INF = 1e9;\n    vector<int> dist(C, INF);\n    deque<int> q;\n    for (int c = 1; c <= m; c++) {\n        if (coastal(c)) {\n            dist[c] = 0;\n            q.push_back(c);\n        }\n    }\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        for (int v : adj[u]) {\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push_back(v);\n            }\n        }\n    }\n    // dist for 0 not used; keep INF.\n\n    // Current grid\n    vector<vector<int>> g = orig;\n\n    // sizes\n    vector<int> sz(C, 0);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) sz[g[i][j]]++;\n\n    // Edge counts ec[min][max] (including 0)\n    vector<vector<int>> ec(C, vector<int>(C, 0));\n    auto addEdge = [&](int u, int v, int delta) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        ec[u][v] += delta;\n    };\n    auto getEdge = [&](int u, int v) -> int {\n        if (u == v) return 0;\n        if (u > v) swap(u, v);\n        return ec[u][v];\n    };\n\n    // init edge counts from g\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = g[i][j];\n            if (i + 1 < n) addEdge(a, g[i + 1][j], +1);\n            if (j + 1 < n) addEdge(a, g[i][j + 1], +1);\n            if (i == 0) addEdge(0, a, +1);\n            if (i == n - 1) addEdge(0, a, +1);\n            if (j == 0) addEdge(0, a, +1);\n            if (j == n - 1) addEdge(0, a, +1);\n        }\n    }\n\n    // BFS connectivity check for removing a cell\n    vector<int> vis(n * n, 0);\n    int vis_stamp = 1;\n\n    auto connected_after_remove = [&](int i, int j, int c) -> bool {\n        int si = -1, sj = -1;\n        int same_deg = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == c) {\n                same_deg++;\n                if (si == -1) { si = ni; sj = nj; }\n            }\n        }\n        if (si == -1) return false;\n        if (same_deg <= 1) return true;\n\n        int target = sz[c] - 1;\n        vis_stamp++;\n        deque<pair<int,int>> qq;\n        qq.push_back({si, sj});\n        vis[idx(si, sj)] = vis_stamp;\n        int cnt = 1;\n        while (!qq.empty()) {\n            auto [x, y] = qq.front(); qq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!inside(nx, ny)) continue;\n                if (nx == i && ny == j) continue;\n                if (g[nx][ny] != c) continue;\n                int id = idx(nx, ny);\n                if (vis[id] == vis_stamp) continue;\n                vis[id] = vis_stamp;\n                qq.push_back({nx, ny});\n                cnt++;\n            }\n        }\n        return cnt == target;\n    };\n\n    auto adjacent_to_zero_or_outside = [&](int i, int j) -> bool {\n        if (is_boundary(i, j)) return true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == 0) return true;\n        }\n        return false;\n    };\n\n    // Core legal move application: recolor (i,j) old -> newc (newc can be 0)\n    auto try_apply = [&](int i, int j, int newc) -> bool {\n        int old = g[i][j];\n        if (old == newc) return false;\n        if (old == 0) return false;\n        if (sz[old] <= 1) return false;\n\n        if (newc == 0) {\n            if (!adjacent_to_zero_or_outside(i, j)) return false;\n        } else {\n            bool touch = false;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj) && g[ni][nj] == newc) { touch = true; break; }\n            }\n            if (!touch) return false;\n        }\n\n        if (!connected_after_remove(i, j, old)) return false;\n\n        // Local edge-count deltas for affected pairs only\n        int keys[16], vals[16], ksz = 0;\n        auto addDelta = [&](int u, int v, int delta) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            int key = u * C + v;\n            for (int t = 0; t < ksz; t++) {\n                if (keys[t] == key) { vals[t] += delta; return; }\n            }\n            keys[ksz] = key;\n            vals[ksz] = delta;\n            ksz++;\n        };\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addDelta(old, d, -1);\n            if (newc != d) addDelta(newc, d, +1);\n        }\n\n        // Check adjacency existence matches req for affected pairs\n        for (int t = 0; t < ksz; t++) {\n            int key = keys[t];\n            int u = key / C;\n            int v = key % C;\n            int cur = getEdge(u, v);\n            int nxt = cur + vals[t];\n            if (nxt < 0) return false;\n            if (req[u][v]) {\n                if (nxt == 0) return false;\n            } else {\n                if (nxt != 0) return false;\n            }\n        }\n\n        // Apply edge updates\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addEdge(old, d, -1);\n            if (newc != d) addEdge(newc, d, +1);\n        }\n\n        // Apply grid + sizes\n        g[i][j] = newc;\n        sz[old]--;\n        if (newc > 0) sz[newc]++;\n\n        return true;\n    };\n\n    // Quick pre-check: if recoloring to b, does it immediately create a forbidden adjacency b-d\n    // just by local neighborhood? (necessary but not sufficient)\n    auto locally_compatible = [&](int i, int j, int b) -> bool {\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d == b) continue;\n            if (!req[b][d]) return false;\n        }\n        return true;\n    };\n\n    uint64_t seed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937 rng((uint32_t)seed);\n\n    Timer timer;\n    const double TL = 1.90;\n    const double PHASE1 = 1.25; // focus on \"flow to coast\" recolors\n\n    // Candidate pool (duplicates allowed)\n    vector<int> cand;\n    cand.reserve(n * n * 10);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cand.push_back(idx(i, j));\n\n    auto push_around = [&](int i, int j) {\n        for (int di = -1; di <= 1; di++) for (int dj = -1; dj <= 1; dj++) {\n            int x = i + di, y = j + dj;\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n        for (int k = 0; k < 4; k++) {\n            int x = i + DX[k], y = j + DY[k];\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n    };\n\n    // Phase 1+2: guided local search\n    while (timer.elapsed() < TL) {\n        if (cand.empty()) break;\n        int pos = (int)(rng() % cand.size());\n        int id = cand[pos];\n        cand[pos] = cand.back();\n        cand.pop_back();\n\n        int i = id / n, j = id % n;\n        int old = g[i][j];\n        if (old == 0) continue;\n\n        // Prefer deletions in phase2, but in phase1 mainly recolor\n        bool allowDelete = (timer.elapsed() > PHASE1);\n\n        // Try delete to 0 if coastal and on 0-frontier\n        if (allowDelete && coastal(old) && adjacent_to_zero_or_outside(i, j)) {\n            // Local necessary condition: any neighbor d>0 must be coastal (since it will become adjacent to 0)\n            bool ok = true;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                int d = inside(ni, nj) ? g[ni][nj] : 0;\n                if (d > 0 && d != old && !coastal(d)) { ok = false; break; }\n            }\n            if (ok && try_apply(i, j, 0)) {\n                push_around(i, j);\n                continue;\n            }\n        }\n\n        // Try recolor to a neighboring color that reduces dist (flow toward coast)\n        int neigh[4];\n        int ns = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (!inside(ni, nj)) continue;\n            int b = g[ni][nj];\n            if (b <= 0 || b == old) continue;\n            neigh[ns++] = b;\n        }\n        if (ns == 0) continue;\n\n        // unique\n        sort(neigh, neigh + ns);\n        ns = (int)(unique(neigh, neigh + ns) - neigh);\n\n        // Sort candidates by dist ascending (best first), tie by coastal preference\n        vector<int> candB(neigh, neigh + ns);\n        sort(candB.begin(), candB.end(), [&](int a, int b) {\n            if (dist[a] != dist[b]) return dist[a] < dist[b];\n            return (int)coastal(a) > (int)coastal(b);\n        });\n\n        // Acceptance: prefer strict dist decrease; allow equal very rarely to help rearrange\n        for (int b : candB) {\n            int dOld = dist[old];\n            int dNew = dist[b];\n            if (dNew > dOld) continue;\n            if (dNew == dOld) {\n                // tiny exploration, mostly in phase2\n                int p = (timer.elapsed() > PHASE1) ? 50 : 200; // 1/50 or 1/200\n                if ((int)(rng() % p) != 0) continue;\n            }\n            if (!locally_compatible(i, j, b)) continue;\n            if (try_apply(i, j, b)) {\n                push_around(i, j);\n                break;\n            }\n        }\n    }\n\n    // Final greedy deletion flood: remove as many coastal frontier cells as possible\n    deque<int> dq;\n    vector<char> inq(n * n, 0);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n        if (is_boundary(i, j)) {\n            int id = idx(i, j);\n            dq.push_back(id);\n            inq[id] = 1;\n        }\n    }\n\n    auto push_del = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        int id = idx(x, y);\n        if (!inq[id]) { inq[id] = 1; dq.push_back(id); }\n    };\n\n    while (!dq.empty() && timer.elapsed() < TL) {\n        int id = dq.front(); dq.pop_front();\n        inq[id] = 0;\n        int i = id / n, j = id % n;\n        int c = g[i][j];\n        if (c == 0) continue;\n        if (!coastal(c)) continue;\n        if (!adjacent_to_zero_or_outside(i, j)) continue;\n\n        bool ok = true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d > 0 && d != c && !coastal(d)) { ok = false; break; }\n        }\n        if (!ok) continue;\n\n        if (try_apply(i, j, 0)) {\n            // push neighbors (new frontier)\n            push_del(i, j);\n            for (int k = 0; k < 4; k++) push_del(i + DX[k], j + DY[k]);\n        }\n    }\n\n    // Final verification (safety). If fail, output original.\n    auto verify = [&]() -> bool {\n        vector<int> cnt(C, 0);\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cnt[g[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cnt[c] == 0) return false;\n\n        // connectivity for colors 1..m\n        vector<int> v(n * n, 0);\n        int st = 1;\n        for (int c = 1; c <= m; c++) {\n            int si = -1, sj = -1;\n            for (int i = 0; i < n && si == -1; i++)\n                for (int j = 0; j < n; j++)\n                    if (g[i][j] == c) { si = i; sj = j; break; }\n            st++;\n            deque<pair<int,int>> qq;\n            qq.push_back({si, sj});\n            v[idx(si, sj)] = st;\n            int got = 1;\n            while (!qq.empty()) {\n                auto [x, y] = qq.front(); qq.pop_front();\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + DX[k], ny = y + DY[k];\n                    if (!inside(nx, ny)) continue;\n                    if (g[nx][ny] != c) continue;\n                    int id2 = idx(nx, ny);\n                    if (v[id2] == st) continue;\n                    v[id2] = st;\n                    qq.push_back({nx, ny});\n                    got++;\n                }\n            }\n            if (got != cnt[c]) return false;\n        }\n\n        // 0 connected to outside (padded BFS)\n        int N = n + 2;\n        auto at = [&](int x, int y) -> int {\n            if (x == 0 || y == 0 || x == N - 1 || y == N - 1) return 0;\n            return g[x - 1][y - 1];\n        };\n        vector<char> vz(N * N, 0);\n        deque<pair<int,int>> q0;\n        q0.push_back({0, 0});\n        vz[0] = 1;\n        while (!q0.empty()) {\n            auto [x, y] = q0.front(); q0.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < N && 0 <= ny && ny < N)) continue;\n                int nid = nx * N + ny;\n                if (vz[nid]) continue;\n                if (at(nx, ny) != 0) continue;\n                vz[nid] = 1;\n                q0.push_back({nx, ny});\n            }\n        }\n        for (int x = 1; x <= n; x++)\n            for (int y = 1; y <= n; y++)\n                if (g[x - 1][y - 1] == 0 && !vz[x * N + y]) return false;\n\n        // adjacency graph equals req\n        vector<vector<char>> outAdj(C, vector<char>(C, 0));\n        auto mark = [&](int u, int v) {\n            if (u == v) return;\n            outAdj[u][v] = outAdj[v][u] = 1;\n        };\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int a = g[i][j];\n                if (i + 1 < n) mark(a, g[i + 1][j]);\n                if (j + 1 < n) mark(a, g[i][j + 1]);\n                if (i == 0) mark(0, a);\n                if (i == n - 1) mark(0, a);\n                if (j == 0) mark(0, a);\n                if (j == n - 1) mark(0, a);\n            }\n        }\n        for (int u = 0; u <= m; u++)\n            for (int v = u + 1; v <= m; v++)\n                if (outAdj[u][v] != req[u][v]) return false;\n\n        return true;\n    };\n\n    if (!verify()) g = orig;\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (j) cout << ' ';\n            cout << g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    using ull = unsigned long long;\n    ull x;\n    explicit XorShift(ull seed = 88172645463325252ULL) : x(seed) {}\n    ull nextUll() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextUll() % (ull)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int cmpLimit = 0; // soft limit for ordering phase; after that, comparisons become deterministic (no queries)\n\n    vector<vector<int>> bins;\n    vector<int> ans;\n\n    vector<vector<int8_t>> itemCmp; // for a<b: 2 unknown, else -1/0/1 meaning wa ? wb\n    XorShift rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    char querySets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) return '='; // no output beyond Q\n        cout << (int)L.size() << \" \" << (int)R.size();\n        for (int x : L) cout << \" \" << x;\n        for (int x : R) cout << \" \" << x;\n        cout << \"\\n\";\n        cout.flush();\n        string s;\n        cin >> s;\n        used++;\n        return s[0];\n    }\n\n    // limited compare: if used >= cmpLimit, no more interactive comparisons; fall back to deterministic by id\n    int cmpItem(int i, int j) {\n        if (i == j) return 0;\n        if (used >= Q) return (i < j ? -1 : +1); // deterministic\n        if (used >= cmpLimit) return (i < j ? -1 : +1); // deterministic (keeps strict ordering)\n\n        int a = min(i, j), b = max(i, j);\n        int8_t &v = itemCmp[a][b];\n        if (v != 2) {\n            int res = (int)v;\n            return (i == a ? res : -res);\n        }\n\n        char r = querySets(vector<int>{i}, vector<int>{j});\n        int res = (r == '<' ? -1 : (r == '>' ? +1 : 0));\n        int store = (i == a ? res : -res);\n        v = (int8_t)store;\n        return res;\n    }\n\n    static int ceil_log2(int n) {\n        int k = 0, p = 1;\n        while (p < n) { p <<= 1; k++; }\n        return k;\n    }\n    static long long clamp_ll(long long x, long long lo, long long hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    // tournament build: fills beaten[winner] lists, returns max item\n    int buildTournament(const vector<int>& items, vector<vector<int>>& beaten) {\n        vector<int> cur = items;\n        while ((int)cur.size() > 1 && used < cmpLimit) {\n            vector<int> nxt;\n            nxt.reserve((cur.size() + 1) / 2);\n            for (int i = 0; i < (int)cur.size(); i += 2) {\n                if (i + 1 == (int)cur.size()) {\n                    nxt.push_back(cur[i]);\n                } else {\n                    int a = cur[i], b = cur[i + 1];\n                    int c = cmpItem(a, b);\n                    int win = (c >= 0 ? a : b);\n                    int lose = (c >= 0 ? b : a);\n                    beaten[win].push_back(lose);\n                    nxt.push_back(win);\n                }\n            }\n            cur.swap(nxt);\n        }\n        return cur[0];\n    }\n\n    // Custom max-heap with explicit comparisons (avoids UB from non-strict comparator)\n    struct MaxHeap {\n        Solver* s;\n        vector<int> h;\n        explicit MaxHeap(Solver* ss) : s(ss) {}\n        bool higher(int a, int b) { // true if a heavier than b\n            int c = s->cmpItem(a, b);\n            if (c == 0) return a > b; // tie-breaker\n            return c > 0;\n        }\n        void push(int x) {\n            h.push_back(x);\n            int i = (int)h.size() - 1;\n            while (i > 0) {\n                int p = (i - 1) / 2;\n                if (!higher(h[i], h[p])) break;\n                swap(h[i], h[p]);\n                i = p;\n            }\n        }\n        int pop() {\n            int ret = h[0];\n            h[0] = h.back();\n            h.pop_back();\n            int n = (int)h.size();\n            int i = 0;\n            while (true) {\n                int l = 2 * i + 1, r = 2 * i + 2;\n                if (l >= n) break;\n                int best = l;\n                if (r < n && higher(h[r], h[l])) best = r;\n                if (!higher(h[best], h[i])) break;\n                swap(h[best], h[i]);\n                i = best;\n            }\n            return ret;\n        }\n        bool empty() const { return h.empty(); }\n        int size() const { return (int)h.size(); }\n    };\n\n    // Approx order via pivot bucketing (heavy->light), within cmpLimit budget (cmpItem handles it)\n    vector<int> approxOrderHeavyByPivots(vector<int> vec) {\n        int n = (int)vec.size();\n        if (n <= 1) return vec;\n\n        for (int i = n - 1; i > 0; i--) swap(vec[i], vec[rng.nextInt(0, i)]);\n\n        auto costForP = [&](int P) -> int {\n            if (P <= 1) return 0;\n            int lg = ceil_log2(P);\n            return P * lg + (n - P) * lg;\n        };\n\n        int remaining = max(0, cmpLimit - used);\n        int P = 2;\n        for (int cand : {32, 16, 8, 4, 2}) {\n            if (cand <= n && costForP(cand) <= remaining) { P = cand; break; }\n        }\n        if (P > n) P = n;\n        if (P < 2) return vec;\n\n        vector<int> piv(vec.begin(), vec.begin() + P);\n        vector<int> rest(vec.begin() + P, vec.end());\n\n        // simple insertion sort on piv (P small)\n        for (int i = 1; i < P; i++) {\n            int x = piv[i];\n            int j = i - 1;\n            while (j >= 0) {\n                int c = cmpItem(piv[j], x);\n                if (c <= 0) break;\n                piv[j + 1] = piv[j];\n                j--;\n            }\n            piv[j + 1] = x;\n        }\n\n        vector<vector<int>> bucket(P + 1);\n        for (int x : rest) {\n            int lo = 0, hi = P;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                int c = cmpItem(x, piv[mid]);\n                if (c < 0) hi = mid;\n                else lo = mid + 1;\n            }\n            bucket[lo].push_back(x);\n        }\n\n        for (auto &b : bucket) {\n            for (int i = (int)b.size() - 1; i > 0; i--) swap(b[i], b[rng.nextInt(0, i)]);\n        }\n\n        vector<int> order;\n        order.reserve(n);\n        for (int j = P; j >= 1; j--) {\n            for (int x : bucket[j]) order.push_back(x);\n            order.push_back(piv[j - 1]);\n        }\n        for (int x : bucket[0]) order.push_back(x);\n\n        // ensure permutation\n        vector<char> seen(N, 0);\n        vector<int> fixed;\n        fixed.reserve(n);\n        for (int x : order) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n        for (int x : vec) if (!seen[x]) fixed.push_back(x);\n        return fixed;\n    }\n\n    void moveItem(int item, int from, int to) {\n        auto &vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); i++) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        ans[item] = to;\n    }\n\n    static int argminSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] < s[idx]) idx = i;\n        return idx;\n    }\n    static int argmaxSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] > s[idx]) idx = i;\n        return idx;\n    }\n\n    int trueLightestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '>') best = i;\n        }\n        return best;\n    }\n    int trueHeaviestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '<') best = i;\n        }\n        return best;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        unsigned long long seed = 1234567ULL;\n        seed ^= (unsigned long long)N * 1000003ULL;\n        seed ^= (unsigned long long)D * 10007ULL;\n        seed ^= (unsigned long long)Q * 97ULL;\n        rng = XorShift(seed);\n\n        used = 0;\n        ans.assign(N, 0);\n        bins.assign(D, {});\n        itemCmp.assign(N, vector<int8_t>(N, 2));\n\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        for (int i = N - 1; i > 0; i--) swap(items[i], items[rng.nextInt(0, i)]);\n\n        // ---- budget split ----\n        int reserveImprove = max(Q / 6, 2 * (D - 1));\n        reserveImprove = min(reserveImprove, 900);\n        int budgetOrder = Q - reserveImprove;\n        // ensure at least tournament possible\n        if (budgetOrder < N - 1) {\n            budgetOrder = N - 1;\n            reserveImprove = Q - budgetOrder;\n            if (reserveImprove < 0) reserveImprove = 0;\n        }\n        // encourage extracting at least top D if possible\n        // (roughly needs about ~ (N-1) + 20D comparisons)\n        if (Q >= (N - 1) + 20 * D && budgetOrder < (N - 1) + 20 * D) {\n            budgetOrder = (N - 1) + 20 * D;\n            reserveImprove = Q - budgetOrder;\n            if (reserveImprove < 0) reserveImprove = 0;\n        }\n\n        cmpLimit = min(Q, budgetOrder);\n\n        // ---- ordering: tournament top-heavy extraction + pivot for rest ----\n        vector<vector<int>> beaten(N);\n        int maxItem = buildTournament(items, beaten);\n\n        vector<int> orderHeavyToLight;\n        orderHeavyToLight.reserve(N);\n\n        vector<char> usedInOrder(N, 0);\n\n        // Extract as many top items as possible within ordering budget\n        MaxHeap heap(this);\n        heap.push(maxItem);\n\n        while (!heap.empty() && used < cmpLimit) {\n            int x = heap.pop();\n            if (usedInOrder[x]) continue;\n            usedInOrder[x] = 1;\n            orderHeavyToLight.push_back(x);\n            for (int y : beaten[x]) if (!usedInOrder[y]) heap.push(y);\n            if ((int)orderHeavyToLight.size() == N) break;\n            // stop early if ordering phase almost done and we already got decent top part\n            if (used + 5 >= cmpLimit && (int)orderHeavyToLight.size() >= D) break;\n        }\n\n        // Remaining items (not in extracted list)\n        vector<int> rest;\n        rest.reserve(N);\n        for (int x : items) if (!usedInOrder[x]) rest.push_back(x);\n\n        if (!rest.empty()) {\n            vector<int> approxRest = approxOrderHeavyByPivots(rest);\n            for (int x : approxRest) orderHeavyToLight.push_back(x);\n        }\n\n        // ensure permutation\n        {\n            vector<char> seen(N, 0);\n            vector<int> fixed;\n            fixed.reserve(N);\n            for (int x : orderHeavyToLight) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n            for (int x : items) if (!seen[x]) fixed.push_back(x);\n            orderHeavyToLight.swap(fixed);\n        }\n\n        // ---- estimate weights from ranks (with smoothing) ----\n        vector<int> orderLightToHeavy(orderHeavyToLight.rbegin(), orderHeavyToLight.rend());\n\n        const long double lambda = 1e-5L;\n        long long M = (long long)100000 * N / D;\n\n        vector<long long> rawW(N, 1);\n        for (int r = 0; r < N; r++) {\n            int it = orderLightToHeavy[r];\n            long double p = (r + 0.5L) / (long double)N;\n            long double val = -logl(1.0L - p) / lambda;\n            long long w = (long long) llround((double)val);\n            w = clamp_ll(w, 1, M);\n            rawW[it] = w;\n        }\n        // smoothing/capping for non-top ranks to reduce sensitivity to rank noise\n        // build rank-wise weights then map back to items\n        vector<long long> rankW(N, 1);\n        for (int r = 0; r < N; r++) rankW[r] = rawW[orderLightToHeavy[r]];\n        for (int r = 1; r < N; r++) rankW[r] = max(rankW[r], rankW[r - 1]); // monotone\n        int protectTop = min(10, N);\n        for (int r = 1; r < N - protectTop; r++) {\n            // cap growth\n            long long cap = rankW[r - 1] + max(10LL, rankW[r - 1] / 5); // +20%\n            if (rankW[r] > cap) rankW[r] = cap;\n        }\n        vector<long long> estW(N, 1);\n        for (int r = 0; r < N; r++) estW[orderLightToHeavy[r]] = clamp_ll(rankW[r], 1, M);\n\n        // ---- initial partition: LPT on estimated weights ----\n        bins.assign(D, {});\n        ans.assign(N, 0);\n        vector<long long> sumEst(D, 0);\n\n        // Seed: top D heavy items, one per bin\n        for (int b = 0; b < D; b++) {\n            int it = orderHeavyToLight[b];\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n        }\n\n        struct Node { long long s; int b; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.s > b.s; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        for (int b = 0; b < D; b++) pq.push({sumEst[b], b});\n\n        for (int idx = D; idx < N; idx++) {\n            int it = orderHeavyToLight[idx];\n            auto cur = pq.top(); pq.pop();\n            int b = cur.b;\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n            pq.push({sumEst[b], b});\n        }\n\n        // ---- offline improvement on estimated weights ----\n        for (int iter = 0; iter < 6000; iter++) {\n            int H = argmaxSum(sumEst);\n            int L = argminSum(sumEst);\n            long long diff = sumEst[H] - sumEst[L];\n            if (diff <= 0) break;\n\n            // try best move H->L\n            int bestX = -1;\n            long long bestAbs = llabs(diff);\n            if ((int)bins[H].size() >= 2) {\n                for (int x : bins[H]) {\n                    long long nd = (sumEst[H] - estW[x]) - (sumEst[L] + estW[x]);\n                    long long absd = llabs(nd);\n                    if (absd < bestAbs) { bestAbs = absd; bestX = x; }\n                }\n            }\n            if (bestX != -1) {\n                sumEst[H] -= estW[bestX];\n                sumEst[L] += estW[bestX];\n                moveItem(bestX, H, L);\n                continue;\n            }\n\n            // try a small swap if move doesn't help\n            int bestA = -1, bestB = -1;\n            bestAbs = llabs(diff);\n\n            vector<int> candH = bins[H], candL = bins[L];\n            sort(candH.begin(), candH.end(), [&](int a, int b){ return estW[a] > estW[b]; });\n            sort(candL.begin(), candL.end(), [&](int a, int b){ return estW[a] < estW[b]; });\n            int takeH = min(3, (int)candH.size());\n            int takeL = min(3, (int)candL.size());\n            for (int i = 0; i < takeH; i++) for (int j = 0; j < takeL; j++) {\n                int a = candH[i], b = candL[j];\n                long long nd = (sumEst[H] - estW[a] + estW[b]) - (sumEst[L] - estW[b] + estW[a]);\n                long long absd = llabs(nd);\n                if (absd < bestAbs) { bestAbs = absd; bestA = a; bestB = b; }\n            }\n            if (bestA == -1) break;\n\n            // apply swap offline\n            sumEst[H] = sumEst[H] - estW[bestA] + estW[bestB];\n            sumEst[L] = sumEst[L] - estW[bestB] + estW[bestA];\n            // swap in bins\n            auto &BH = bins[H];\n            auto &BL = bins[L];\n            for (int &x : BH) if (x == bestA) { x = bestB; break; }\n            for (int &x : BL) if (x == bestB) { x = bestA; break; }\n            ans[bestA] = L;\n            ans[bestB] = H;\n        }\n\n        // ---- interactive refinement ----\n        cmpLimit = Q; // allow interactive comparisons in refinement too\n\n        int steps = 0;\n        while (used < Q) {\n            int remQ = Q - used;\n            if (remQ < 2) break;\n\n            int H = argmaxSum(sumEst);\n            int L = argminSum(sumEst);\n            if (H == L) break;\n\n            // occasionally find true extremes if budget is large\n            if (remQ >= 2 * (D - 1) + 5 && steps % 8 == 0) {\n                int tL = trueLightestBin();\n                if (used >= Q) break;\n                int tH = trueHeaviestBin();\n                if (used >= Q) break;\n                L = tL; H = tH;\n                if (H == L) break;\n            }\n\n            // verify direction\n            char dir = querySets(bins[H], bins[L]); // H ? L\n            if (used >= Q) break;\n            if (dir == '=') break;\n            if (dir == '<') swap(H, L);\n            if (H == L) break;\n\n            // 1) try a guided move (few probes)\n            bool applied = false;\n            if ((int)bins[H].size() >= 2 && remQ >= 3) {\n                vector<int> cand = bins[H];\n                sort(cand.begin(), cand.end(), [&](int a, int b){ return estW[a] < estW[b]; }); // light..heavy\n\n                int lo = 0, hi = (int)cand.size() - 1;\n                int chosen = -1;\n                int probe = min(4, Q - used);\n\n                for (int k = 0; k < probe && lo <= hi && used < Q; k++) {\n                    int mid = (lo + hi) >> 1;\n                    int x = cand[mid];\n\n                    vector<int> A;\n                    A.reserve(bins[H].size() - 1);\n                    for (int y : bins[H]) if (y != x) A.push_back(y);\n                    if (A.empty()) break;\n                    vector<int> B = bins[L];\n                    B.push_back(x);\n\n                    char r = querySets(A, B); // newH ? newL\n                    if (r == '=') { chosen = x; break; }\n                    if (r == '>') lo = mid + 1; // still heavy -> need heavier x\n                    else hi = mid - 1;          // overshoot -> need lighter x\n\n                    chosen = x; // fallback last tried\n                }\n\n                if (chosen != -1 && (int)bins[H].size() >= 2) {\n                    sumEst[H] -= estW[chosen];\n                    sumEst[L] += estW[chosen];\n                    moveItem(chosen, H, L);\n                    applied = true;\n                }\n            }\n\n            // 2) if not applied or we have budget, try a small swap validated by one query\n            if (!applied && (Q - used) >= 1) {\n                vector<int> candH = bins[H], candL = bins[L];\n                sort(candH.begin(), candH.end(), [&](int a, int b){ return estW[a] > estW[b]; });\n                sort(candL.begin(), candL.end(), [&](int a, int b){ return estW[a] < estW[b]; });\n\n                int takeH = min(3, (int)candH.size());\n                int takeL = min(3, (int)candL.size());\n\n                int bestA = -1, bestB = -1;\n                long long bestAbs = llabs(sumEst[H] - sumEst[L]);\n\n                for (int i = 0; i < takeH; i++) for (int j = 0; j < takeL; j++) {\n                    int a = candH[i], b = candL[j];\n                    long long nd = (sumEst[H] - estW[a] + estW[b]) - (sumEst[L] - estW[b] + estW[a]);\n                    long long absd = llabs(nd);\n                    if (absd < bestAbs) { bestAbs = absd; bestA = a; bestB = b; }\n                }\n\n                if (bestA != -1) {\n                    // Validate swap by comparing newH vs newL (1 query)\n                    vector<int> newH = bins[H], newL = bins[L];\n                    for (int &x : newH) if (x == bestA) { x = bestB; break; }\n                    for (int &x : newL) if (x == bestB) { x = bestA; break; }\n\n                    char r = querySets(newH, newL);\n                    if (r != '<') { // accept if not clear overshoot (keep H >= L)\n                        // apply swap\n                        sumEst[H] = sumEst[H] - estW[bestA] + estW[bestB];\n                        sumEst[L] = sumEst[L] - estW[bestB] + estW[bestA];\n                        auto &BH = bins[H];\n                        auto &BL = bins[L];\n                        for (int &x : BH) if (x == bestA) { x = bestB; break; }\n                        for (int &x : BL) if (x == bestB) { x = bestA; break; }\n                        ans[bestA] = L;\n                        ans[bestB] = H;\n                        applied = true;\n                    }\n                }\n            }\n\n            steps++;\n            if (!applied) break;\n        }\n\n        // ---- dummy queries to reach exactly Q ----\n        while (used < Q) querySets(vector<int>{0}, vector<int>{1});\n\n        // final clamp (paranoia)\n        for (int i = 0; i < N; i++) if (ans[i] < 0 || ans[i] >= D) ans[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << \"\\n\";\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 200;\nstatic constexpr int M = 10;\nstatic constexpr int INF = INT_MAX;\n\nstruct Weights {\n    double wHeight = 0.06;\n    double wMinUrg = 230.0;\n    double wTopUrg = 85.0;\n    double wMinAtTopExtra = 260.0;\n\n    double badTopBase = 4200.0;\n    double badTopPerCnt = 220.0;     // per moved item that is > dest.top\n    double badMinBase = 2600.0;\n    double badMinPerCnt = 260.0;     // per moved item that is > dest.min (scaled by urgency)\n\n    double emptyReserve = 35.0;\n\n    int lookahead = 14;      // simulation removals\n    int destCand = 6;        // destinations tried per action\n    int cmax = 6;            // max chunk size (top peeling) considered\n};\n\nstruct Result {\n    long long energy = (1LL<<60);\n    vector<pair<int,int>> ops;\n};\n\nstatic inline uint64_t xorshift64(uint64_t &x) {\n    x ^= x << 7;\n    x ^= x >> 9;\n    return x;\n}\n\nstruct State {\n    array<array<int, N>, M> a{};\n    array<int, M> sz{};\n\n    array<int, N + 1> posS{};\n    array<int, N + 1> posI{};\n\n    array<int, M> top{};\n    array<int, M> mn{};\n    array<int, M> posMinFromTop{};\n\n    void recalc(int i) {\n        int h = sz[i];\n        if (h == 0) {\n            top[i] = INF;\n            mn[i] = INF;\n            posMinFromTop[i] = 0;\n            return;\n        }\n        top[i] = a[i][h - 1];\n        int best = INF, bestIdx = 0;\n        for (int j = 0; j < h; j++) {\n            int v = a[i][j];\n            if (v < best) {\n                best = v;\n                bestIdx = j;\n            }\n        }\n        mn[i] = best;\n        posMinFromTop[i] = (h - 1) - bestIdx;\n    }\n\n    void initFromInput(const vector<vector<int>> &init) {\n        for (int i = 0; i < M; i++) {\n            sz[i] = (int)init[i].size();\n            for (int j = 0; j < sz[i]; j++) {\n                a[i][j] = init[i][j];\n                posS[a[i][j]] = i;\n                posI[a[i][j]] = j;\n            }\n        }\n        for (int i = 0; i < M; i++) recalc(i);\n    }\n\n    inline pair<int,int> locate(int v) const {\n        return {posS[v], posI[v]};\n    }\n    inline bool isOnTop(int v) const {\n        auto [s, idx] = locate(v);\n        return s >= 0 && idx == sz[s] - 1;\n    }\n\n    inline void popTop(int s) {\n        int v = a[s][sz[s] - 1];\n        sz[s]--;\n        posS[v] = -1;\n        posI[v] = -1;\n        recalc(s);\n    }\n\n    inline void moveSuffix(int s, int start, int d) {\n        int k = sz[s] - start;\n        int base = sz[d];\n        for (int i = 0; i < k; i++) {\n            int x = a[s][start + i];\n            a[d][base + i] = x;\n            posS[x] = d;\n            posI[x] = base + i;\n        }\n        sz[d] += k;\n        sz[s] = start;\n        recalc(s);\n        recalc(d);\n    }\n};\n\nstruct MovePlan {\n    // operation 1: move suffix starting at 'start' from stack s to stack d\n    int s = -1;\n    int d = -1;\n    int start = -1;\n    int len = 0;\n    int v = -1;\n    long long eval = (1LL<<62);\n};\n\nstruct Solver {\n    State init;\n\n    explicit Solver(const vector<vector<int>> &st0) {\n        init.initFromInput(st0);\n    }\n\n    // Collect moved values into buf[0..len)\n    static inline int collectMoved(const State &st, int s, int start, int *buf) {\n        int len = st.sz[s] - start;\n        for (int i = 0; i < len; i++) buf[i] = st.a[s][start + i];\n        return len;\n    }\n\n    static inline int maxOfBuf(const int *buf, int len) {\n        int mx = 0;\n        for (int i = 0; i < len; i++) mx = max(mx, buf[i]);\n        return mx;\n    }\n\n    static inline double destPenaltyWithBuf(\n        const State &st,\n        int t,\n        int s, int d,\n        const int *buf, int len,\n        int bufMax,\n        const Weights &w\n    ) {\n        if (d == s) return 1e100;\n\n        int h = st.sz[d];\n        if (h == 0) {\n            // safe but slightly reserved\n            return w.emptyReserve + w.wHeight * double(len);\n        }\n\n        int top = st.top[d];\n        int mn = st.mn[d];\n        int posMin = st.posMinFromTop[d];\n\n        double deltaMin = double(mn - t);\n        double deltaTop = double(top - t);\n        if (deltaMin < 1.0) deltaMin = 1.0;\n        if (deltaTop < 1.0) deltaTop = 1.0;\n\n        // counts of \"blocking\" items after placing buf on destination\n        int cntAboveTop = 0;\n        int cntAboveMin = 0;\n        if (top != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > top) cntAboveTop++;\n        }\n        if (mn != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > mn) cntAboveMin++;\n        }\n\n        double p = 0.0;\n        p += w.wHeight * double(h + len);\n        p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n        p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n\n        if (posMin == 0) {\n            p += w.wMinAtTopExtra * double(len + 1) / (deltaMin + 1.0);\n        }\n\n        // Strong penalties when we bury a smaller top/min under larger moved values\n        if (cntAboveTop > 0) {\n            // also factor severity by how much bigger the move max is than top (mildly)\n            p += w.badTopBase + w.badTopPerCnt * cntAboveTop + 2.0 * max(0, bufMax - top);\n        }\n        if (cntAboveMin > 0) {\n            p += (w.badMinBase + w.badMinPerCnt * cntAboveMin) / (deltaMin + 1.0);\n        }\n\n        return p;\n    }\n\n    static int chooseDestBase(const State &st, int t, int s, int start, const Weights &w) {\n        int len = st.sz[s] - start;\n        int mx = 0;\n        for (int i = start; i < st.sz[s]; i++) mx = max(mx, st.a[s][i]);\n\n        // safe stack: mn > mx\n        int bestSafe = -1;\n        int bestH = INF;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > mx) {\n                int h = st.sz[d];\n                if (h < bestH) {\n                    bestH = h;\n                    bestSafe = d;\n                }\n            }\n        }\n        if (bestSafe != -1) return bestSafe;\n\n        // otherwise minimize a cheap proxy\n        double bestP = 1e100;\n        int bestD = (s + 1) % M;\n        for (int d = 0; d < M; d++) if (d != s) {\n            int h = st.sz[d];\n            int top = st.top[d];\n            int mn = st.mn[d];\n            double deltaMin = max(1.0, double(mn - t));\n            double deltaTop = max(1.0, double(top - t));\n            double p = 0.0;\n            if (h == 0) p += w.emptyReserve;\n            p += w.wHeight * double(h + len);\n            p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n            p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n            if (top < mx) p += w.badTopBase;\n            if (mn < mx) p += w.badMinBase / (deltaMin + 1.0);\n            if (p < bestP) { bestP = p; bestD = d; }\n        }\n        return bestD;\n    }\n\n    static long long simulateEnergy(State st, int tStart, int maxRemovals, const Weights &w) {\n        long long e = 0;\n        int t = tStart;\n        int removed = 0;\n\n        while (t <= N && removed < maxRemovals) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                st.popTop(s);\n                t++;\n                removed++;\n            } else {\n                int start = idx + 1;\n                int len = st.sz[s] - start;\n                int d = chooseDestBase(st, t, s, start, w);\n                st.moveSuffix(s, start, d);\n                e += (long long)len + 1;\n            }\n        }\n        return e;\n    }\n\n    // Decide the next move when t is not on top:\n    // either move whole above-t pile, or peel top c boxes, using 1-step search + lookahead.\n    static MovePlan decideMove(State const &st, int t, const Weights &w, uint64_t &rng, int opsLeft) {\n        auto [s, idx] = st.locate(t);\n        int kTotal = st.sz[s] - idx - 1;\n\n        MovePlan best;\n        best.eval = (1LL<<62);\n\n        // If operation budget is tight, avoid peeling.\n        bool tight = (opsLeft < 250);\n\n        // Precompute whole-pile info\n        int bufAll[N];\n        int startAll = idx + 1;\n        int lenAll = collectMoved(st, s, startAll, bufAll);\n        int maxAll = maxOfBuf(bufAll, lenAll);\n\n        bool existsSafeForAll = false;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > maxAll) { existsSafeForAll = true; break; }\n        }\n\n        // Gate: peeling search mainly when whole move has no safe destination or pile is small\n        bool doPeelSearch = (!tight) && (!existsSafeForAll || kTotal <= 10);\n\n        // Candidate actions: always include whole move, plus top-c peel moves if enabled\n        vector<pair<int,int>> actions; // (start, len)\n        actions.push_back({startAll, lenAll});\n        if (doPeelSearch) {\n            int cmax = min(w.cmax, kTotal);\n            for (int c = 1; c <= cmax; c++) {\n                int start = st.sz[s] - c;\n                if (start <= idx) continue; // must not include t\n                actions.push_back({start, c});\n            }\n        }\n\n        // Evaluate each action by trying best few destinations (ranked by penalty) and simulating\n        for (auto [start, len] : actions) {\n            int buf[N];\n            int got = collectMoved(st, s, start, buf);\n            (void)got;\n            int bufMax = maxOfBuf(buf, len);\n\n            // Rank destinations\n            vector<pair<double,int>> ranked;\n            ranked.reserve(M - 1);\n            for (int d = 0; d < M; d++) if (d != s) {\n                double p = destPenaltyWithBuf(st, t, s, d, buf, len, bufMax, w);\n                // tiny noise to diversify between trials\n                p += double(int(xorshift64(rng) % 1000)) * 1e-9;\n                ranked.push_back({p, d});\n            }\n            sort(ranked.begin(), ranked.end());\n\n            int D = min(w.destCand, (int)ranked.size());\n            for (int i = 0; i < D; i++) {\n                int d = ranked[i].second;\n                State st2 = st;\n                st2.moveSuffix(s, start, d);\n                long long score = (long long)len + 1;\n                score += simulateEnergy(st2, t, w.lookahead, w);\n\n                // mild bias: avoid excessive peeling unless it helps\n                if (len <= w.cmax && len != lenAll) score += 1; // tiny +1 (not energy), just tie-break\n\n                if (score < best.eval) {\n                    best.eval = score;\n                    best.s = s;\n                    best.d = d;\n                    best.start = start;\n                    best.len = len;\n                    best.v = st.a[s][start];\n                }\n            }\n        }\n\n        // Fallback (shouldn't happen)\n        if (best.s < 0) {\n            best.s = s;\n            best.start = startAll;\n            best.len = lenAll;\n            best.v = st.a[s][startAll];\n            best.d = (s + 1) % M;\n            best.eval = (long long)lenAll + 1;\n        }\n        return best;\n    }\n\n    Result run(const Weights &w, uint64_t seed) {\n        uint64_t rng = seed;\n        State st = init;\n\n        vector<pair<int,int>> ops;\n        ops.reserve(2500);\n\n        long long energy = 0;\n        int t = 1;\n\n        while (t <= N) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                ops.push_back({t, 0});\n                st.popTop(s);\n                t++;\n            } else {\n                int opsLeft = 5000 - (int)ops.size();\n                MovePlan mv = decideMove(st, t, w, rng, opsLeft);\n\n                ops.push_back({mv.v, mv.d + 1});\n                st.moveSuffix(mv.s, mv.start, mv.d);\n                energy += (long long)mv.len + 1;\n            }\n\n            if ((int)ops.size() > 5000) break;\n        }\n\n        return Result{energy, std::move(ops)};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> initStacks(M);\n    for (int i = 0; i < M; i++) {\n        initStacks[i].resize(n / m);\n        for (int j = 0; j < n / m; j++) cin >> initStacks[i][j];\n    }\n\n    Solver solver(initStacks);\n\n    Weights base;\n\n    auto t0 = chrono::high_resolution_clock::now();\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result best;\n    best.energy = (1LL<<60);\n\n    int trials = 0;\n    while (true) {\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - t0).count();\n        if (elapsed > 1.93) break;\n\n        Weights w = base;\n\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)trials;\n        uint64_t rng = seed;\n\n        auto rand01 = [&]() -> double {\n            return (double)(xorshift64(rng) % 1000000) / 1000000.0;\n        };\n        auto mult = [&](double x, double lo, double hi) {\n            return x * (lo + (hi - lo) * rand01());\n        };\n\n        if (trials > 0) {\n            w.wHeight = mult(w.wHeight, 0.7, 1.4);\n            w.wMinUrg = mult(w.wMinUrg, 0.75, 1.35);\n            w.wTopUrg = mult(w.wTopUrg, 0.75, 1.35);\n            w.wMinAtTopExtra = mult(w.wMinAtTopExtra, 0.75, 1.45);\n\n            w.badTopBase = mult(w.badTopBase, 0.7, 1.4);\n            w.badTopPerCnt = mult(w.badTopPerCnt, 0.7, 1.6);\n\n            w.badMinBase = mult(w.badMinBase, 0.7, 1.5);\n            w.badMinPerCnt = mult(w.badMinPerCnt, 0.7, 1.6);\n\n            w.emptyReserve = mult(w.emptyReserve, 0.6, 1.6);\n\n            // vary lookahead slightly\n            double r = rand01();\n            if (r < 0.25) w.lookahead = 12;\n            else if (r < 0.55) w.lookahead = 14;\n            else w.lookahead = 16;\n\n            // chunking aggressiveness\n            double r2 = rand01();\n            if (r2 < 0.30) w.cmax = 5;\n            else if (r2 < 0.70) w.cmax = 6;\n            else w.cmax = 7;\n\n            // destination candidates\n            double r3 = rand01();\n            if (r3 < 0.30) w.destCand = 5;\n            else if (r3 < 0.75) w.destCand = 6;\n            else w.destCand = 7;\n        }\n\n        Result cur = solver.run(w, seed);\n        if ((int)cur.ops.size() <= 5000 && cur.energy < best.energy) {\n            best = std::move(cur);\n        }\n\n        trials++;\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << \" \" << i << \"\\n\";\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline char oppositeDir(char c){\n    if(c=='U') return 'D';\n    if(c=='D') return 'U';\n    if(c=='L') return 'R';\n    return 'L';\n}\nstatic inline int dirId(char c){\n    if(c=='U') return 0;\n    if(c=='D') return 1;\n    if(c=='L') return 2;\n    return 3;\n}\nstatic const char DIRCH[4] = {'U','D','L','R'};\n\nstruct Timer{\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()){}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct XorShift{\n    uint64_t x=88172645463325252ull;\n    explicit XorShift(uint64_t seed=0){ if(seed) x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int nextInt(int lo,int hi){\n        return lo + (int)(next() % (uint64_t)(hi-lo+1));\n    }\n};\n\nstruct Edge {\n    int to;\n    int eid;\n    char mv;\n};\n\nstruct AnalysisResult{\n    bool ok=false;\n    long long sumSq=(1LL<<62);\n    long double metric=1e100L;\n    vector<int> pos;          // size L+1, pos[0]=0, pos[i+1]=arrival after i-th move\n    vector<int> first, last;\n    vector<int> bestGapLen;\n    vector<int> bestGapStart;\n};\n\nstruct Solver{\n    int N,V;\n    vector<string> h,v;\n    vector<int> d;\n    vector<array<int,4>> nxt;\n\n    // undirected graph for bridge/component\n    vector<vector<Edge>> g;\n    vector<int> eu, ev;            // endpoints per eid\n    vector<char> emv_uv, emv_vu;   // move char from eu->ev and ev->eu\n    vector<char> isBridge;\n\n    // components of graph without bridges\n    int C = 0;\n    vector<int> compId;\n    vector<vector<int>> compVerts;\n    vector<long long> compSumD;\n    vector<int> compPortal;        // portal vertex in component (endpoint towards root in bridge tree)\n    vector<int> compParent;        // parent component in bridge tree\n\n    vector<vector<int>> compTopNodes;  // per component, top-K vertices by d\n    vector<string> compTour;           // precomputed internal loop tour from portal back to portal (within component)\n\n    // BFS buffers for global shortest path\n    vector<int> bfsDist, bfsPrev;\n    vector<char> bfsPrevMove;\n\n    // BFS buffers for restricted path\n    vector<int> rDist, rPrev;\n    vector<char> rPrevMove;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    int id(int i,int j) const { return i*N + j; }\n\n    void readInput(){\n        cin >> N;\n        V = N*N;\n        h.resize(N-1);\n        v.resize(N);\n        for(int i=0;i<N-1;i++) cin >> h[i];\n        for(int i=0;i<N;i++) cin >> v[i];\n        d.assign(V,0);\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int x; cin >> x;\n            d[id(i,j)] = x;\n        }\n\n        nxt.assign(V, array<int,4>{-1,-1,-1,-1});\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int u=id(i,j);\n            if(i>0   && h[i-1][j]=='0') nxt[u][0]=id(i-1,j);\n            if(i<N-1 && h[i][j]=='0')   nxt[u][1]=id(i+1,j);\n            if(j>0   && v[i][j-1]=='0') nxt[u][2]=id(i,j-1);\n            if(j<N-1 && v[i][j]=='0')   nxt[u][3]=id(i,j+1);\n        }\n\n        bfsDist.assign(V,-1);\n        bfsPrev.assign(V,-1);\n        bfsPrevMove.assign(V,0);\n\n        rDist.assign(V,-1);\n        rPrev.assign(V,-1);\n        rPrevMove.assign(V,0);\n    }\n\n    // Build undirected graph with edge ids\n    void buildGraph(){\n        g.assign(V, {});\n        eu.clear(); ev.clear();\n        emv_uv.clear(); emv_vu.clear();\n\n        // add each undirected edge once (u<v)\n        for(int u=0;u<V;u++){\n            for(int k=0;k<4;k++){\n                int w = nxt[u][k];\n                if(w<0) continue;\n                if(u < w){\n                    int eid = (int)eu.size();\n                    eu.push_back(u);\n                    ev.push_back(w);\n                    char mv = DIRCH[k];\n                    emv_uv.push_back(mv);                 // u->w\n                    emv_vu.push_back(oppositeDir(mv));    // w->u\n                    g[u].push_back(Edge{w, eid, mv});\n                    g[w].push_back(Edge{u, eid, oppositeDir(mv)});\n                }\n            }\n        }\n        isBridge.assign(eu.size(), 0);\n    }\n\n    // Tarjan bridges\n    void findBridges(){\n        vector<int> tin(V,-1), low(V,0);\n        int timer=0;\n        function<void(int,int)> dfs = [&](int vtx,int peid){\n            tin[vtx]=low[vtx]=timer++;\n            for(auto &e: g[vtx]){\n                if(e.eid==peid) continue;\n                int to=e.to;\n                if(tin[to]!=-1){\n                    low[vtx]=min(low[vtx], tin[to]);\n                }else{\n                    dfs(to, e.eid);\n                    low[vtx]=min(low[vtx], low[to]);\n                    if(low[to] > tin[vtx]){\n                        isBridge[e.eid]=1;\n                    }\n                }\n            }\n        };\n        dfs(0, -1);\n    }\n\n    void buildComponentsAndBridgeTree(){\n        compId.assign(V, -1);\n        compVerts.clear();\n        compSumD.clear();\n\n        // components ignoring bridges\n        for(int s=0;s<V;s++){\n            if(compId[s]!=-1) continue;\n            int cid = (int)compVerts.size();\n            compVerts.push_back({});\n            compSumD.push_back(0);\n            deque<int> q;\n            compId[s]=cid;\n            q.push_back(s);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                compVerts[cid].push_back(u);\n                compSumD[cid] += d[u];\n                for(auto &e: g[u]){\n                    if(isBridge[e.eid]) continue;\n                    int w=e.to;\n                    if(compId[w]!=-1) continue;\n                    compId[w]=cid;\n                    q.push_back(w);\n                }\n            }\n        }\n        C = (int)compVerts.size();\n\n        // build bridge tree adjacency (store endpoints)\n        struct CEdge { int to; int u; int v; int eid; };\n        vector<vector<CEdge>> cg(C);\n        for(int eid=0; eid<(int)eu.size(); eid++){\n            if(!isBridge[eid]) continue;\n            int a=eu[eid], b=ev[eid];\n            int ca=compId[a], cb=compId[b];\n            if(ca==cb) continue;\n            cg[ca].push_back(CEdge{cb, a, b, eid});\n            cg[cb].push_back(CEdge{ca, b, a, eid});\n        }\n\n        int rootC = compId[0];\n        compParent.assign(C, -1);\n        compPortal.assign(C, -1);\n        compPortal[rootC] = 0;\n\n        deque<int> q;\n        q.push_back(rootC);\n        compParent[rootC] = rootC;\n\n        while(!q.empty()){\n            int c=q.front(); q.pop_front();\n            for(auto &ce: cg[c]){\n                if(compParent[ce.to]!=-1) continue;\n                compParent[ce.to] = c;\n                compPortal[ce.to] = ce.v; // endpoint inside child component\n                q.push_back(ce.to);\n            }\n        }\n    }\n\n    // Global BFS shortest path moves\n    string shortestPathMoves(int s,int t){\n        if(s==t) return {};\n        fill(bfsDist.begin(), bfsDist.end(), -1);\n        deque<int> q;\n        bfsDist[s]=0;\n        bfsPrev[s]=-1;\n        q.push_back(s);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            for(auto &e: g[u]){\n                int w=e.to;\n                if(bfsDist[w]!=-1) continue;\n                bfsDist[w]=bfsDist[u]+1;\n                bfsPrev[w]=u;\n                bfsPrevMove[w]=e.mv;\n                if(w==t){ q.clear(); break; }\n                q.push_back(w);\n            }\n        }\n        if(bfsDist[t]==-1) return {};\n        string path;\n        int cur=t;\n        while(cur!=s){\n            char mv=bfsPrevMove[cur];\n            path.push_back(mv);\n            cur=bfsPrev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // BFS distances from src to all (global)\n    void bfsDistancesGlobal(int src, vector<int>& dist){\n        dist.assign(V, -1);\n        deque<int> q;\n        dist[src]=0;\n        q.push_back(src);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            for(auto &e: g[u]){\n                int w=e.to;\n                if(dist[w]!=-1) continue;\n                dist[w]=dist[u]+1;\n                q.push_back(w);\n            }\n        }\n    }\n\n    // Restricted shortest path inside component (no bridges)\n    string shortestPathMovesInComp(int s,int t,int cid){\n        if(s==t) return {};\n        fill(rDist.begin(), rDist.end(), -1);\n        deque<int> q;\n        rDist[s]=0;\n        rPrev[s]=-1;\n        q.push_back(s);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            for(auto &e: g[u]){\n                if(isBridge[e.eid]) continue;\n                int w=e.to;\n                if(compId[w]!=cid) continue;\n                if(rDist[w]!=-1) continue;\n                rDist[w]=rDist[u]+1;\n                rPrev[w]=u;\n                rPrevMove[w]=e.mv;\n                if(w==t){ q.clear(); break; }\n                q.push_back(w);\n            }\n        }\n        if(rDist[t]==-1) return {};\n        string path;\n        int cur=t;\n        while(cur!=s){\n            char mv=rPrevMove[cur];\n            path.push_back(mv);\n            cur=rPrev[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    void precomputeComponentTours(){\n        compTopNodes.assign(C, {});\n        compTour.assign(C, \"\");\n\n        // choose heavy components (excluding root) by compSumD\n        int rootC = compId[0];\n        vector<pair<long long,int>> comps;\n        for(int cid=0; cid<C; cid++){\n            if(cid==rootC) continue;\n            if(compPortal[cid] < 0) continue;\n            comps.push_back({compSumD[cid], cid});\n        }\n        sort(comps.begin(), comps.end(), greater<>());\n        int H = min<int>(12, (int)comps.size());\n\n        vector<char> isHeavy(C, 0);\n        for(int i=0;i<H;i++) isHeavy[comps[i].second]=1;\n\n        // for each heavy component: pick top nodes and build internal tour\n        for(int cid=0; cid<C; cid++){\n            if(!isHeavy[cid]) continue;\n            int start = compPortal[cid];\n            if(start < 0) continue;\n\n            auto &verts = compVerts[cid];\n            vector<int> vv = verts;\n            sort(vv.begin(), vv.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n            int K = min<int>(20, (int)vv.size());\n            vv.resize(K);\n            // ensure start included\n            if(find(vv.begin(), vv.end(), start) == vv.end()){\n                vv.push_back(start);\n            }\n            // unique\n            sort(vv.begin(), vv.end());\n            vv.erase(unique(vv.begin(), vv.end()), vv.end());\n            sort(vv.begin(), vv.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n            compTopNodes[cid] = vv;\n\n            // build greedy nearest-neighbor tour inside component starting/ending at start\n            vector<int> targets = vv;\n            // remove start from remaining\n            targets.erase(remove(targets.begin(), targets.end(), start), targets.end());\n\n            string tour;\n            int cur = start;\n\n            while(!targets.empty()){\n                // BFS restricted distances from cur\n                fill(rDist.begin(), rDist.end(), -1);\n                deque<int> q;\n                rDist[cur]=0;\n                q.push_back(cur);\n                while(!q.empty()){\n                    int u=q.front(); q.pop_front();\n                    for(auto &e: g[u]){\n                        if(isBridge[e.eid]) continue;\n                        int w=e.to;\n                        if(compId[w]!=cid) continue;\n                        if(rDist[w]!=-1) continue;\n                        rDist[w]=rDist[u]+1;\n                        q.push_back(w);\n                    }\n                }\n                int best = -1, bestDist = INT_MAX, bestD=-1;\n                for(int t: targets){\n                    int dist = rDist[t];\n                    if(dist<0) continue;\n                    if(dist < bestDist || (dist==bestDist && d[t] > bestD)){\n                        bestDist = dist;\n                        bestD = d[t];\n                        best = t;\n                    }\n                }\n                if(best==-1) break; // should not happen\n\n                string p = shortestPathMovesInComp(cur, best, cid);\n                tour += p;\n                cur = best;\n                targets.erase(remove(targets.begin(), targets.end(), best), targets.end());\n            }\n\n            // return to start\n            string back = shortestPathMovesInComp(cur, start, cid);\n            tour += back;\n\n            compTour[cid] = tour;\n        }\n    }\n\n    // Tree building / Euler for randomized base\n    void buildSpanningTree(vector<int>& parent, vector<char>& parentDir, vector<int>& order,\n                           XorShift& rng, int gamma, int noiseScale){\n        parent.assign(V, -1);\n        parentDir.assign(V, '?');\n        vector<int> depth(V,0);\n        vector<char> vis(V,0);\n        order.clear(); order.reserve(V);\n\n        struct Cand{ int key; int p; int x; char dir; };\n        struct Cmp{ bool operator()(const Cand& a,const Cand& b) const { return a.key < b.key; } };\n        priority_queue<Cand, vector<Cand>, Cmp> pq;\n\n        auto pushNeighbors = [&](int u){\n            int du = depth[u];\n            for(int k=0;k<4;k++){\n                int w = nxt[u][k];\n                if(w<0 || vis[w]) continue;\n                int noise = noiseScale ? rng.nextInt(0, noiseScale) : 0;\n                int key = d[w]*1024 - gamma*(du+1)*1024 + noise;\n                pq.push(Cand{key, u, w, DIRCH[k]});\n            }\n        };\n\n        vis[0]=1;\n        order.push_back(0);\n        pushNeighbors(0);\n\n        while((int)order.size() < V){\n            if(pq.empty()) break;\n            auto c=pq.top(); pq.pop();\n            if(vis[c.x]) continue;\n            vis[c.x]=1;\n            parent[c.x]=c.p;\n            parentDir[c.x]=c.dir;\n            depth[c.x]=depth[c.p]+1;\n            order.push_back(c.x);\n            pushNeighbors(c.x);\n        }\n        // fallback BFS tree if needed\n        if((int)order.size() < V){\n            parent.assign(V,-1);\n            parentDir.assign(V,'?');\n            order.clear(); order.reserve(V);\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent[w]=u;\n                    parentDir[w]=DIRCH[k];\n                    q.push_back(w);\n                    order.push_back(w);\n                }\n            }\n        }\n    }\n\n    string buildEulerRoute(const vector<int>& parent, const vector<char>& parentDir,\n                           const vector<int>& order, XorShift& rng, int childNoise){\n        vector<vector<int>> children(V);\n        for(int x=1;x<V;x++){\n            int p=parent[x];\n            if(p>=0) children[p].push_back(x);\n        }\n        vector<long long> sub(V);\n        for(int i=0;i<V;i++) sub[i]=d[i];\n        for(int idx=(int)order.size()-1; idx>=1; --idx){\n            int x=order[idx];\n            int p=parent[x];\n            if(p>=0) sub[p]+=sub[x];\n        }\n        for(int u=0;u<V;u++){\n            auto &ch=children[u];\n            sort(ch.begin(), ch.end(), [&](int a,int b){\n                long long ka = sub[a]*1024 + d[a]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                long long kb = sub[b]*1024 + d[b]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                if(ka!=kb) return ka>kb;\n                return a<b;\n            });\n        }\n        string route;\n        route.reserve(2*(V-1)+10);\n        function<void(int)> dfs = [&](int u){\n            for(int x: children[u]){\n                route.push_back(parentDir[x]);\n                dfs(x);\n                route.push_back(oppositeDir(parentDir[x]));\n            }\n        };\n        dfs(0);\n        return route;\n    }\n\n    bool simulatePositions(const string& route, vector<int>& pos){\n        int L=(int)route.size();\n        pos.assign(L+1, 0);\n        int cur=0;\n        for(int i=0;i<L;i++){\n            int k=dirId(route[i]);\n            int nx=nxt[cur][k];\n            if(nx<0) return false;\n            cur=nx;\n            pos[i+1]=cur;\n        }\n        return cur==0;\n    }\n\n    AnalysisResult analyzeRoute(const string& route){\n        AnalysisResult res;\n        int L=(int)route.size();\n        if(L<=0) return res;\n        if(!simulatePositions(route, res.pos)) return res;\n\n        res.first.assign(V,-1);\n        res.last.assign(V,-1);\n        res.bestGapLen.assign(V,-1);\n        res.bestGapStart.assign(V,0);\n\n        long long sumSq=0;\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=res.pos[i+1];\n            if(res.first[vtx]==-1){\n                res.first[vtx]=res.last[vtx]=t;\n            }else{\n                int gap=t-res.last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                if(gap > res.bestGapLen[vtx]){\n                    res.bestGapLen[vtx]=gap;\n                    res.bestGapStart[vtx]=res.last[vtx];\n                }\n                res.last[vtx]=t;\n            }\n        }\n        for(int vtx=0;vtx<V;vtx++){\n            if(res.first[vtx]==-1) return res; // unvisited\n            int gap=(res.first[vtx]+L)-res.last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n            if(gap > res.bestGapLen[vtx]){\n                res.bestGapLen[vtx]=gap;\n                res.bestGapStart[vtx]=res.last[vtx];\n            }\n        }\n        res.sumSq=sumSq;\n        res.metric=(long double)sumSq/(long double)L;\n        res.ok=true;\n        return res;\n    }\n\n    long double computeMetric(const string& route, vector<int>& first, vector<int>& last){\n        int L=(int)route.size();\n        if(L<=0) return 1e100L;\n        vector<int> pos;\n        if(!simulatePositions(route, pos)) return 1e100L;\n\n        fill(first.begin(), first.end(), -1);\n        fill(last.begin(), last.end(), -1);\n        long long sumSq=0;\n\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=pos[i+1];\n            if(first[vtx]==-1) first[vtx]=last[vtx]=t;\n            else{\n                int gap=t-last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                last[vtx]=t;\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++){\n            if(first[vtx]==-1) return 1e100L;\n            int gap=(first[vtx]+L)-last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n        }\n        return (long double)sumSq/(long double)L;\n    }\n\n    // first-visit order from Euler positions\n    vector<int> firstVisitOrderFromEuler(const string& euler){\n        vector<int> pos;\n        simulatePositions(euler, pos);\n        vector<char> seen(V,0);\n        vector<int> ord;\n        ord.reserve(V+1);\n        seen[0]=1; ord.push_back(0);\n        for(int i=1;i<(int)pos.size();i++){\n            int vtx=pos[i];\n            if(!seen[vtx]){\n                seen[vtx]=1;\n                ord.push_back(vtx);\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++) if(!seen[vtx]) ord.push_back(vtx);\n        ord.push_back(0);\n        return ord;\n    }\n\n    // Convert vertex order to route via shortest paths. If exceeds maxLen, return empty.\n    string buildRouteFromVertexOrder(const vector<int>& ord, int maxLen=100000){\n        string route;\n        for(int i=0;i+1<(int)ord.size();i++){\n            string p = shortestPathMoves(ord[i], ord[i+1]);\n            if(p.empty() && ord[i]!=ord[i+1]) return {};\n            if((int)route.size() + (int)p.size() > maxLen) return {};\n            route += p;\n        }\n        return route;\n    }\n\n    // choose insertion position near midpoint of representative gap, minimizing distToTarget at route positions\n    pair<int,int> chooseInsertPosNearGap(const AnalysisResult& ar, int repVtx, const vector<int>& distToTarget){\n        int L=(int)ar.pos.size()-1;\n        int startT = ar.bestGapStart[repVtx];\n        int len = ar.bestGapLen[repVtx];\n        long long midT = (long long)startT + len/2;\n        int baseP = (int)((midT + 1) % L);\n\n        int W = min(50, max(3, len/5));\n        int bestP=baseP;\n        int bestDist=INT_MAX;\n        int bestAbs=INT_MAX;\n\n        for(int off=-W; off<=W; off++){\n            int p=baseP+off;\n            p%=L; if(p<0) p+=L;\n            int at = ar.pos[p];\n            int dist = distToTarget[at];\n            if(dist<0) continue;\n            int aoff=abs(off);\n            if(dist < bestDist || (dist==bestDist && aoff < bestAbs)){\n                bestDist=dist;\n                bestAbs=aoff;\n                bestP=p;\n            }\n        }\n        return {bestP, bestDist};\n    }\n\n    void improveByDetours(string& route, Timer& timer, double endTimeSec){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        // cache heavy component list (those with precomputed tour)\n        vector<int> heavyComps;\n        for(int cid=0; cid<C; cid++){\n            if(!compTour[cid].empty() && cid!=compId[0]) heavyComps.push_back(cid);\n        }\n\n        while(timer.elapsed() < endTimeSec){\n            AnalysisResult ar = analyzeRoute(route);\n            if(!ar.ok) break;\n            long double curMetric = ar.metric;\n            int L=(int)route.size();\n            if(L>=100000) break;\n\n            struct Cand{\n                int type; // 0: single vertex, 1: component\n                int key;  // vtx or cid\n                int insertPos;\n                long long estBenefit;\n                int estAddLen;\n                long double ratio;\n            };\n            vector<Cand> cands;\n            cands.reserve(200);\n\n            // --- single-vertex candidates ---\n            vector<pair<long long,int>> keys;\n            keys.reserve(V);\n            for(int vtx=0; vtx<V; vtx++){\n                int g = ar.bestGapLen[vtx];\n                if(g<=1) continue;\n                long long k = 1LL*d[vtx]*g*g;\n                keys.push_back({k, vtx});\n            }\n            if(keys.empty()) break;\n            int Kv = min<int>(50, (int)keys.size());\n            nth_element(keys.begin(), keys.begin()+Kv, keys.end(),\n                        [&](auto& a, auto& b){ return a.first > b.first; });\n            keys.resize(Kv);\n            sort(keys.begin(), keys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n            vector<int> distToVtx;\n            for(auto [_, vtx] : keys){\n                if(timer.elapsed() >= endTimeSec) break;\n                int g = ar.bestGapLen[vtx];\n                if(g<=1) continue;\n                bfsDistancesGlobal(vtx, distToVtx);\n                auto [p, dist] = chooseInsertPosNearGap(ar, vtx, distToVtx);\n                if(dist<=0) continue;\n                int addLen = 2*dist;\n                if(L + addLen > 100000) continue;\n\n                int a=g/2, b=g-a;\n                long long benefit = 1LL*d[vtx]*(1LL*g*g - 1LL*a*a - 1LL*b*b);\n                if(benefit<=0) continue;\n                cands.push_back(Cand{0, vtx, p, benefit, addLen, (long double)benefit/addLen});\n            }\n\n            // --- component candidates (bridge-based) ---\n            // for each heavy component: benefit = sum over top nodes of split benefit, cost = 2*dist(to portal)+tourLen\n            for(int cid: heavyComps){\n                if(timer.elapsed() >= endTimeSec) break;\n                int portal = compPortal[cid];\n                if(portal < 0) continue;\n                const string& tour = compTour[cid];\n                if(tour.empty()) continue;\n\n                // representative = node in top list maximizing d*gap^2 (current)\n                int rep = portal;\n                long long repKey = -1;\n                for(int u: compTopNodes[cid]){\n                    int g = ar.bestGapLen[u];\n                    if(g<=1) continue;\n                    long long k = 1LL*d[u]*g*g;\n                    if(k > repKey){\n                        repKey = k;\n                        rep = u;\n                    }\n                }\n                if(repKey < 0) continue;\n\n                vector<int> distToPortal;\n                bfsDistancesGlobal(portal, distToPortal);\n                auto [p, dist] = chooseInsertPosNearGap(ar, rep, distToPortal);\n                if(dist<=0) continue;\n                int addLen = 2*dist + (int)tour.size();\n                if(L + addLen > 100000) continue;\n\n                long long benefitSum = 0;\n                for(int u: compTopNodes[cid]){\n                    int g = ar.bestGapLen[u];\n                    if(g<=1) continue;\n                    int a=g/2, b=g-a;\n                    benefitSum += 1LL*d[u]*(1LL*g*g - 1LL*a*a - 1LL*b*b);\n                }\n                if(benefitSum<=0) continue;\n\n                cands.push_back(Cand{1, cid, p, benefitSum, addLen, (long double)benefitSum/addLen});\n            }\n\n            if(cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                return a.ratio > b.ratio;\n            });\n\n            int M = min<int>(18, (int)cands.size());\n            long double bestMetric = curMetric;\n            int bestIdx = -1;\n            string bestDet;\n\n            for(int i=0;i<M;i++){\n                if(timer.elapsed() >= endTimeSec) break;\n                const auto& c = cands[i];\n                int p = c.insertPos;\n                int startV = ar.pos[p];\n\n                string det;\n                if(c.type==0){\n                    int vtx = c.key;\n                    string go = shortestPathMoves(startV, vtx);\n                    if(go.empty()) continue;\n                    det = go;\n                    det.reserve(go.size()*2);\n                    for(int k=(int)go.size()-1;k>=0;k--) det.push_back(oppositeDir(go[k]));\n                }else{\n                    int cid = c.key;\n                    int portal = compPortal[cid];\n                    const string& tour = compTour[cid];\n                    if(tour.empty()) continue;\n                    string go = shortestPathMoves(startV, portal);\n                    if(go.empty() && startV!=portal) continue;\n                    det.reserve(go.size()*2 + tour.size());\n                    det += go;\n                    det += tour;\n                    for(int k=(int)go.size()-1;k>=0;k--) det.push_back(oppositeDir(go[k]));\n                }\n\n                if((int)route.size() + (int)det.size() > 100000) continue;\n\n                route.insert((size_t)p, det);\n                long double met = computeMetric(route, tmpFirst, tmpLast);\n                route.erase((size_t)p, det.size());\n\n                if(met + 1e-18L < bestMetric){\n                    bestMetric = met;\n                    bestIdx = i;\n                    bestDet = std::move(det);\n                }\n            }\n\n            if(bestIdx == -1) break;\n            route.insert((size_t)cands[bestIdx].insertPos, bestDet);\n        }\n    }\n\n    void simplifyBacktracks(string& route, Timer& timer, double endTimeSec){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n        int tries=0;\n        while(timer.elapsed() < endTimeSec && tries < 200){\n            tries++;\n            vector<int> pos;\n            if(!simulatePositions(route, pos)) return;\n            int L=(int)route.size();\n            vector<int> cnt(V,0);\n            for(int i=1;i<=L;i++) cnt[pos[i]]++;\n\n            long double base = computeMetric(route, tmpFirst, tmpLast);\n            bool improved=false;\n\n            for(int i=0;i+1<L;i++){\n                if(timer.elapsed() >= endTimeSec) break;\n                char a=route[i], b=route[i+1];\n                if(oppositeDir(a) != b) continue;\n                int midV = pos[i+1];\n                if(cnt[midV] <= 1) continue; // would delete only visit\n\n                string cand;\n                cand.reserve(L-2);\n                cand.append(route.begin(), route.begin()+i);\n                cand.append(route.begin()+i+2, route.end());\n\n                long double met = computeMetric(cand, tmpFirst, tmpLast);\n                if(met + 1e-18L < base){\n                    route.swap(cand);\n                    improved=true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n    }\n\n    void solve(){\n        Timer timer;\n        double TL = 1.95;\n        XorShift rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        buildGraph();\n        findBridges();\n        buildComponentsAndBridgeTree();\n        precomputeComponentTours();\n\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        string bestRoute;\n        long double bestMetric = 1e100L;\n\n        int starts = 8;\n        vector<int> parent, order;\n        vector<char> parentDir;\n\n        for(int s=0; s<starts; s++){\n            if(timer.elapsed() > TL) break;\n\n            int gamma = 8 + (s%5)*4;            // 8,12,16,20,24\n            int noiseScale = 6000 + s*2500;\n            int childNoise = 1500 + s*900;\n\n            buildSpanningTree(parent, parentDir, order, rng, gamma, noiseScale);\n            string euler = buildEulerRoute(parent, parentDir, order, rng, childNoise);\n\n            vector<int> ord = firstVisitOrderFromEuler(euler);\n            string route = buildRouteFromVertexOrder(ord, 100000);\n            if(route.empty()){\n                // fallback to Euler (always safe length)\n                route = euler;\n            }\n\n            // time slice\n            double now = timer.elapsed();\n            double remain = max(0.0, TL - now);\n            double per = remain / max(1, starts - s);\n            double endTime = min(TL, now + per * 0.95);\n\n            improveByDetours(route, timer, endTime);\n            simplifyBacktracks(route, timer, min(TL, endTime + 0.03));\n\n            long double met = computeMetric(route, tmpFirst, tmpLast);\n            if(met < bestMetric){\n                bestMetric = met;\n                bestRoute = std::move(route);\n            }\n        }\n\n        if(bestRoute.empty()){\n            // ultimate fallback: simple DFS-like Euler from BFS tree\n            vector<int> parent2(V,-1), order2;\n            vector<char> pd2(V,'?');\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order2.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent2[w]=u;\n                    pd2[w]=DIRCH[k];\n                    q.push_back(w);\n                    order2.push_back(w);\n                }\n            }\n            bestRoute = buildEulerRoute(parent2, pd2, order2, rng, 0);\n        }\n\n        cout << bestRoute << \"\\n\";\n    }\n};\n\nint main(){\n    Solver s;\n    s.readInput();\n    s.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static const auto t0 = steady_clock::now();\n    return duration<double>(steady_clock::now() - t0).count();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; i++) cin >> grid[i];\n    vector<string> t(M);\n    for (int i = 0; i < M; i++) cin >> t[i];\n\n    // Contest fixed constraint: N = 15\n    constexpr int NFIX = 15;\n    constexpr int V = NFIX * NFIX; // 225\n    auto cell_id = [&](int r, int c) { return r * N + c; };\n    int startCell = cell_id(si, sj);\n\n    // letter at each cell\n    array<int, V> letterAtCell{};\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int id = cell_id(r, c);\n        letterAtCell[id] = grid[r][c] - 'A';\n    }\n\n    // cells by letter\n    array<vector<int>, 26> cellsByLetter;\n    for (int id = 0; id < N * N; id++) {\n        cellsByLetter[letterAtCell[id]].push_back(id);\n    }\n\n    int maxOcc = 0;\n    for (int c = 0; c < 26; c++) maxOcc = max(maxOcc, (int)cellsByLetter[c].size());\n\n    // distCell[a][b] = Manhattan distance\n    vector<array<uint8_t, V>> distCell(V);\n    for (int a = 0; a < V; a++) {\n        int ar = a / N, ac = a % N;\n        for (int b = 0; b < V; b++) {\n            int br = b / N, bc = b % N;\n            distCell[a][b] = (uint8_t)(abs(ar - br) + abs(ac - bc));\n        }\n    }\n\n    // words as ints\n    vector<array<int, 5>> w(M);\n    vector<int> firstL(M), lastL(M);\n    for (int i = 0; i < M; i++) {\n        for (int k = 0; k < 5; k++) w[i][k] = t[i][k] - 'A';\n        firstL[i] = w[i][0];\n        lastL[i] = w[i][4];\n    }\n\n    auto max_overlap = [&](int a, int b) -> int {\n        for (int l = 4; l >= 1; --l) {\n            bool ok = true;\n            for (int i = 0; i < l; i++) {\n                if (t[a][5 - l + i] != t[b][i]) { ok = false; break; }\n            }\n            if (ok) return l;\n        }\n        return 0;\n    };\n\n    vector<vector<uint8_t>> ov(M, vector<uint8_t>(M, 0));\n    for (int i = 0; i < M; i++) for (int j = 0; j < M; j++) if (i != j) {\n        ov[i][j] = (uint8_t)max_overlap(i, j);\n    }\n\n    // Reusable buffers for small DPs\n    vector<int> dp(maxOcc), ndp(maxOcc);\n\n    auto cost_type_from_cell = [&](int idx, int sCell, int from) -> int {\n        if (from >= 5) return 0;\n        const auto &ww = w[idx];\n\n        const auto &L0 = cellsByLetter[ww[from]];\n        int m0 = (int)L0.size();\n        for (int i = 0; i < m0; i++) dp[i] = (int)distCell[sCell][L0[i]] + 1;\n\n        int mprev = m0;\n        for (int k = from + 1; k < 5; k++) {\n            const auto &Lprev = cellsByLetter[ww[k-1]];\n            const auto &Lcur  = cellsByLetter[ww[k]];\n            int mc = (int)Lcur.size();\n            // dp corresponds to Lprev; sizes match by construction:\n            // At first step dp size=m0 for L0, which equals Lprev when k=from+1\n            // Then we update dp to match Lcur.\n            (void)Lprev;\n            for (int i = 0; i < mc; i++) {\n                int best = INT_MAX;\n                int ccell = Lcur[i];\n                for (int j = 0; j < mprev; j++) {\n                    int cand = dp[j] + (int)distCell[cellsByLetter[ww[k-1]][j]][ccell] + 1;\n                    if (cand < best) best = cand;\n                }\n                ndp[i] = best;\n            }\n            for (int i = 0; i < mc; i++) dp[i] = ndp[i];\n            mprev = mc;\n        }\n\n        int best = INT_MAX;\n        for (int i = 0; i < mprev; i++) best = min(best, dp[i]);\n        return best;\n    };\n\n    // Precompute word costs\n    vector<int> startCostWord(M, 0);\n    vector<array<int, 26>> fromLetterCost(M);\n    vector<array<int, 5>> overlapSuffixCost(M);\n\n    vector<int> fullFromCell(V);\n\n    for (int i = 0; i < M; i++) {\n        fromLetterCost[i].fill(INT_MAX);\n        overlapSuffixCost[i].fill(INT_MAX);\n\n        for (int s = 0; s < V; s++) fullFromCell[s] = cost_type_from_cell(i, s, 0);\n        startCostWord[i] = fullFromCell[startCell];\n\n        // min over cells grouped by letter using letterAtCell\n        for (int s = 0; s < V; s++) {\n            int x = letterAtCell[s];\n            fromLetterCost[i][x] = min(fromLetterCost[i][x], fullFromCell[s]);\n        }\n\n        for (int l = 1; l <= 4; l++) {\n            int prevLetter = w[i][l-1];\n            int best = INT_MAX;\n            for (int s : cellsByLetter[prevLetter]) {\n                best = min(best, cost_type_from_cell(i, s, l));\n            }\n            overlapSuffixCost[i][l] = best;\n        }\n    }\n\n    // edgeCost[a][b]\n    vector<vector<int>> edgeCost(M, vector<int>(M, 0));\n    for (int a = 0; a < M; a++) for (int b = 0; b < M; b++) if (a != b) {\n        int l = ov[a][b];\n        edgeCost[a][b] = (l == 0 ? fromLetterCost[b][lastL[a]] : overlapSuffixCost[b][l]);\n    }\n\n    auto link_cost = [&](int prev, int cur) -> int {\n        if (cur < 0) return 0;\n        if (prev < 0) return startCostWord[cur];\n        return edgeCost[prev][cur];\n    };\n\n    auto eval_perm = [&](const vector<int>& P) -> int {\n        long long cost = startCostWord[P[0]];\n        for (int i = 1; i < M; i++) cost += edgeCost[P[i-1]][P[i]];\n        return (int)cost;\n    };\n\n    auto build_string_from_perm = [&](const vector<int>& P, string& S) {\n        S.clear();\n        S.reserve(5 * M);\n        S += t[P[0]];\n        for (int i = 1; i < M; i++) {\n            int l = ov[P[i-1]][P[i]];\n            S.append(t[P[i]].begin() + l, t[P[i]].end());\n        }\n    };\n\n    // exact DP cost only\n    vector<int> dpPrev, dpCur;\n    dpPrev.reserve(maxOcc);\n    dpCur.reserve(maxOcc);\n\n    auto solve_exact_cost = [&](const string& S) -> int {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int mc = (int)layer.size();\n            dpCur.assign(mc, INF);\n\n            if (k == 0) {\n                for (int i = 0; i < mc; i++) dpCur[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                int mp = (int)prevLayer.size();\n                for (int i = 0; i < mc; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    for (int j = 0; j < mp; j++) {\n                        int cand = dpPrev[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    dpCur[i] = best;\n                }\n            }\n            dpPrev.swap(dpCur);\n        }\n        return *min_element(dpPrev.begin(), dpPrev.end());\n    };\n\n    // exact DP with path reconstruction for final output\n    auto solve_exact_path = [&](const string& S) -> pair<int, vector<int>> {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        vector<vector<int16_t>> parent(L);\n\n        vector<int> dpp, dpc;\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int mc = (int)layer.size();\n            dpc.assign(mc, INF);\n            parent[k].assign(mc, (int16_t)-1);\n\n            if (k == 0) {\n                for (int i = 0; i < mc; i++) dpc[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                int mp = (int)prevLayer.size();\n                for (int i = 0; i < mc; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    int16_t bestj = -1;\n                    for (int j = 0; j < mp; j++) {\n                        int cand = dpp[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) { best = cand; bestj = (int16_t)j; }\n                    }\n                    dpc[i] = best;\n                    parent[k][i] = bestj;\n                }\n            }\n            dpp.swap(dpc);\n        }\n\n        int bestCost = INF, bestIdx = 0;\n        for (int i = 0; i < (int)dpp.size(); i++) {\n            if (dpp[i] < bestCost) { bestCost = dpp[i]; bestIdx = i; }\n        }\n\n        vector<int> path(L);\n        int idx = bestIdx;\n        for (int k = L - 1; k >= 0; k--) {\n            int c = S[k] - 'A';\n            path[k] = cellsByLetter[c][idx];\n            idx = parent[k][idx];\n        }\n        return {bestCost, path};\n    };\n\n    // ----- SA delta functions -----\n    auto delta_swap = [&](const vector<int>& P, int i, int j) -> int {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n        int a = P[i], b = P[j];\n\n        auto get = [&](int k) -> int {\n            if (k == i) return b;\n            if (k == j) return a;\n            return P[k];\n        };\n        auto contrib_at = [&](int k, bool after) -> int {\n            if (k < 0 || k >= M) return 0;\n            int cur = after ? get(k) : P[k];\n            int prev;\n            if (k == 0) prev = -1;\n            else prev = after ? get(k - 1) : P[k - 1];\n            return link_cost(prev, cur);\n        };\n\n        int oldv = 0, newv = 0;\n        int idxs[4] = {i, i + 1, j, j + 1};\n        // unique them (small)\n        for (int x = 0; x < 4; x++) {\n            int k = idxs[x];\n            bool dup = false;\n            for (int y = 0; y < x; y++) if (idxs[y] == k) dup = true;\n            if (dup) continue;\n            oldv += contrib_at(k, false);\n            newv += contrib_at(k, true);\n        }\n        return newv - oldv;\n    };\n\n    auto delta_insert = [&](const vector<int>& P, int i, int j) -> int {\n        // move element at i to position j (like rotate-based in code below)\n        if (i == j) return 0;\n        int x = P[i];\n        if (i < j) {\n            // remove (i) then insert after position j-1 (original j)\n            int A = (i == 0 ? -1 : P[i - 1]);\n            int B = P[i + 1];                // exists because i<j => i<=M-2\n            int Y = P[j];\n            int Z = (j == M - 1 ? -1 : P[j + 1]);\n\n            int delta = 0;\n            // remove A->x and x->B, add A->B\n            delta -= link_cost(A, x);\n            delta -= link_cost(x, B);\n            delta += link_cost(A, B);\n\n            // remove Y->Z, add Y->x and x->Z\n            if (Z != -1) {\n                delta -= link_cost(Y, Z);\n                delta += link_cost(Y, x);\n                delta += link_cost(x, Z);\n            } else {\n                // inserting at end\n                delta += link_cost(Y, x);\n            }\n            return delta;\n        } else {\n            // i > j : insert x before position j\n            int A = (j == 0 ? -1 : P[j - 1]);\n            int B = P[j];\n\n            int C = P[i - 1];\n            int D = (i == M - 1 ? -1 : P[i + 1]);\n\n            int delta = 0;\n            // remove A->B, add A->x and x->B\n            delta -= link_cost(A, B);\n            delta += link_cost(A, x);\n            delta += link_cost(x, B);\n\n            // remove C->x and x->D, add C->D\n            delta -= link_cost(C, x);\n            if (D != -1) {\n                delta -= link_cost(x, D);\n                delta += link_cost(C, D);\n            }\n            return delta;\n        }\n    };\n\n    // block move: move segment [l..r] to before position p (0..M), with p not in [l..r+1]\n    auto delta_block = [&](const vector<int>& P, int l, int r, int p) -> int {\n        if (l > r) swap(l, r);\n        int len = r - l + 1;\n        if (p >= l && p <= r + 1) return 0; // invalid/no-op\n\n        int A = (l == 0 ? -1 : P[l - 1]);\n        int B = P[l];\n        int C = P[r];\n        int D = (r == M - 1 ? -1 : P[r + 1]);\n\n        int E, F;\n        if (p == 0) { E = -1; F = P[0]; }\n        else if (p == M) { E = P[M - 1]; F = -1; }\n        else { E = P[p - 1]; F = P[p]; }\n\n        // Old edges: A->B, C->D, E->F\n        // New edges: A->D, E->B, C->F\n        int oldv = link_cost(A, B) + link_cost(C, D) + link_cost(E, F);\n        int newv = link_cost(A, D) + link_cost(E, B) + link_cost(C, F);\n        return newv - oldv;\n    };\n\n    // ----- Build initial permutations -----\n    uint64_t seed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    auto greedy_init = [&]() -> vector<int> {\n        vector<int> P;\n        P.reserve(M);\n        vector<char> used(M, 0);\n\n        int start = 0;\n        for (int i = 1; i < M; i++) if (startCostWord[i] < startCostWord[start]) start = i;\n        P.push_back(start);\n        used[start] = 1;\n\n        for (int it = 1; it < M; it++) {\n            int cur = P.back();\n            int best = -1, bestv = INT_MAX;\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int v = edgeCost[cur][j];\n                if (v < bestv) { bestv = v; best = j; }\n            }\n            used[best] = 1;\n            P.push_back(best);\n        }\n        return P;\n    };\n\n    auto random_init = [&]() -> vector<int> {\n        vector<int> P(M);\n        iota(P.begin(), P.end(), 0);\n        shuffle(P.begin(), P.end(), rng);\n        return P;\n    };\n\n    double tstart = now_sec();\n    const double TIME_END = tstart + 1.93;\n    const double TIME_SA_END = TIME_END - 0.55;\n    const double TIME_EXACT_END = TIME_END - 0.08;\n\n    vector<int> bestPerm = greedy_init();\n    int bestApprox = eval_perm(bestPerm);\n\n    // ----- SA (approx objective) -----\n    int restart = 0;\n    while (now_sec() < TIME_SA_END) {\n        restart++;\n        vector<int> P = (restart % 3 == 1 ? greedy_init() : random_init());\n        int curCost = eval_perm(P);\n\n        int localBest = curCost;\n        vector<int> localBestP = P;\n\n        double sliceStart = now_sec();\n        double sliceEnd = min(TIME_SA_END, sliceStart + 0.20);\n\n        const double Tbegin = 35.0;\n        const double Tend = 0.25;\n\n        while (now_sec() < sliceEnd) {\n            double prog = (now_sec() - sliceStart) / max(1e-9, (sliceEnd - sliceStart));\n            double temp = Tbegin * pow(Tend / Tbegin, prog);\n\n            double r = ur(rng);\n            int d = 0;\n\n            if (r < 0.55) {\n                // swap\n                int i = (int)(ur(rng) * M);\n                int j = (int)(ur(rng) * M);\n                while (j == i) j = (int)(ur(rng) * M);\n                d = delta_swap(P, i, j);\n                if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                    swap(P[i], P[j]);\n                    curCost += d;\n                }\n            } else if (r < 0.85) {\n                // insert (single)\n                int i = (int)(ur(rng) * M);\n                int j = (int)(ur(rng) * M);\n                while (j == i) j = (int)(ur(rng) * M);\n                d = delta_insert(P, i, j);\n                if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                    if (i < j) rotate(P.begin() + i, P.begin() + i + 1, P.begin() + j + 1);\n                    else       rotate(P.begin() + j, P.begin() + i,     P.begin() + i + 1);\n                    curCost += d;\n                }\n            } else {\n                // block move\n                int l = (int)(ur(rng) * M);\n                int r2 = (int)(ur(rng) * M);\n                if (l > r2) swap(l, r2);\n                if (l == r2) continue;\n                int p = (int)(ur(rng) * (M + 1));\n                if (p >= l && p <= r2 + 1) continue; // invalid/no-op\n\n                d = delta_block(P, l, r2, p);\n                if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                    if (p < l) {\n                        // bring [l..r2] before p\n                        rotate(P.begin() + p, P.begin() + l, P.begin() + r2 + 1);\n                    } else { // p > r2+1\n                        // move [l..r2] to before p\n                        rotate(P.begin() + l, P.begin() + r2 + 1, P.begin() + p);\n                    }\n                    curCost += d;\n                }\n            }\n\n            if (curCost < localBest) {\n                localBest = curCost;\n                localBestP = P;\n            }\n        }\n\n        if (localBest < bestApprox) {\n            bestApprox = localBest;\n            bestPerm = localBestP;\n        }\n    }\n\n    // ----- Exact-cost hill climb (true DP cost) -----\n    string S;\n    build_string_from_perm(bestPerm, S);\n    int bestExactCost = solve_exact_cost(S);\n    vector<int> bestExactPerm = bestPerm;\n\n    while (now_sec() < TIME_EXACT_END) {\n        vector<int> P = bestExactPerm;\n\n        double r = ur(rng);\n        if (r < 0.50) {\n            int i = (int)(ur(rng) * M);\n            int j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            swap(P[i], P[j]);\n        } else if (r < 0.80) {\n            int i = (int)(ur(rng) * M);\n            int j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            if (i < j) rotate(P.begin() + i, P.begin() + i + 1, P.begin() + j + 1);\n            else       rotate(P.begin() + j, P.begin() + i,     P.begin() + i + 1);\n        } else {\n            int l = (int)(ur(rng) * M);\n            int r2 = (int)(ur(rng) * M);\n            if (l > r2) swap(l, r2);\n            if (l == r2) continue;\n            int p = (int)(ur(rng) * (M + 1));\n            if (p >= l && p <= r2 + 1) continue;\n            if (p < l) rotate(P.begin() + p, P.begin() + l, P.begin() + r2 + 1);\n            else       rotate(P.begin() + l, P.begin() + r2 + 1, P.begin() + p);\n        }\n\n        build_string_from_perm(P, S);\n        int c = solve_exact_cost(S);\n        if (c < bestExactCost) {\n            bestExactCost = c;\n            bestExactPerm = move(P);\n        }\n    }\n\n    // Final exact path output\n    build_string_from_perm(bestExactPerm, S);\n    auto [finalCost, pathCells] = solve_exact_path(S);\n\n    for (int cell : pathCells) {\n        cout << (cell / N) << ' ' << (cell % N) << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Query {\n    vector<uint64_t> bits;   // bitmask over N^2 cells\n    vector<int> cells;       // list of indices for output\n    int k;                   // number of cells\n    double obs;              // estimated true sum v(S)\n    double w;                // weight in objective\n    bool exact;              // drill => exact\n};\n\nstruct Placement {\n    int di, dj;\n    vector<uint64_t> bits;\n    vector<int> cells;           // indices\n    vector<int16_t> inter;       // intersection counts for each query (appended)\n    vector<int> neigh;           // neighbor placement indices (shifts)\n};\n\nstruct Field {\n    vector<Placement> ps;\n};\n\nstruct Solution {\n    vector<int> idx; // chosen placement per field\n    double cost;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    // deterministic hash mixing\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Solver {\n    int N, M;\n    double eps;\n    int N2;\n    int L; // number of uint64 blocks\n    int op_limit;\n    int ops = 0;\n\n    vector<Field> fields;\n    vector<Query> queries;\n\n    vector<int> drilledVal; // -1 unknown else exact v\n    int drilledCnt = 0;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, double eps_) : N(N_), M(M_), eps(eps_) {\n        N2 = N * N;\n        L = (N2 + 63) / 64;\n        op_limit = 2 * N2;\n        drilledVal.assign(N2, -1);\n        rng.seed((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    }\n\n    // --- interactive I/O ---\n    int drillCell(int i, int j) {\n        cout << \"q 1 \" << i << \" \" << j << endl;\n        ops++;\n        int v;\n        if (!(cin >> v)) exit(0);\n        return v;\n    }\n\n    int divineCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"q \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int y;\n        if (!(cin >> y)) exit(0);\n        return y;\n    }\n\n    int answerCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        cout << \"a \" << d;\n        for (auto &p: ps) cout << \" \" << p.first << \" \" << p.second;\n        cout << endl;\n        ops++;\n        int ok;\n        if (!(cin >> ok)) exit(0);\n        return ok;\n    }\n\n    // reserve enough operations to drill all remaining cells + final answer\n    bool canSpendOps(int extra) const {\n        int remainingToDrill = N2 - drilledCnt;\n        // need remainingToDrill drills + 1 final answer after spending extra\n        return ops + extra + remainingToDrill + 1 <= op_limit;\n    }\n\n    // --- bit helpers ---\n    inline bool bitGet(const vector<uint64_t>& b, int idx) const {\n        return (b[idx >> 6] >> (idx & 63)) & 1ULL;\n    }\n    inline void bitSet(vector<uint64_t>& b, int idx) const {\n        b[idx >> 6] |= 1ULL << (idx & 63);\n    }\n    int popcountAnd(const vector<uint64_t>& a, const vector<uint64_t>& b) const {\n        int s = 0;\n        for (int t = 0; t < L; t++) s += __builtin_popcountll(a[t] & b[t]);\n        return s;\n    }\n\n    // --- build placements for each field ---\n    void buildPlacements(const vector<vector<pair<int,int>>>& shapes) {\n        fields.resize(M);\n        for (int f = 0; f < M; f++) {\n            const auto& shp = shapes[f];\n            int maxI = 0, maxJ = 0;\n            for (auto [x,y]: shp) {\n                maxI = max(maxI, x);\n                maxJ = max(maxJ, y);\n            }\n            int diMax = N - maxI - 1;\n            int djMax = N - maxJ - 1;\n            // map translation -> placement index\n            vector<vector<int>> mp(diMax+1, vector<int>(djMax+1, -1));\n\n            for (int di = 0; di <= diMax; di++) {\n                for (int dj = 0; dj <= djMax; dj++) {\n                    Placement p;\n                    p.di = di; p.dj = dj;\n                    p.bits.assign(L, 0ULL);\n                    p.cells.reserve(shp.size());\n                    for (auto [x,y]: shp) {\n                        int i = di + x;\n                        int j = dj + y;\n                        int idx = i*N + j;\n                        p.cells.push_back(idx);\n                        bitSet(p.bits, idx);\n                    }\n                    fields[f].ps.push_back(std::move(p));\n                    mp[di][dj] = (int)fields[f].ps.size()-1;\n                }\n            }\n            // neighbors by +/-1 shifts\n            for (auto &p: fields[f].ps) {\n                int di = p.di, dj = p.dj;\n                static int dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n                for (auto &d: dd) {\n                    int ndi = di + d[0], ndj = dj + d[1];\n                    if (0 <= ndi && ndi <= diMax && 0 <= ndj && ndj <= djMax) {\n                        int ni = mp[ndi][ndj];\n                        if (ni >= 0) p.neigh.push_back(ni);\n                    }\n                }\n            }\n        }\n    }\n\n    // --- add query + update all placement intersection arrays ---\n    void addQuery(const vector<int>& cellIdx, const vector<uint64_t>& bits, int k, int rawResp, bool exact) {\n        Query q;\n        q.bits = bits;\n        q.cells = cellIdx;\n        q.k = k;\n        q.exact = exact;\n\n        if (exact) {\n            q.obs = (double)rawResp;\n            q.w = 1e6; // very strong constraint\n        } else {\n            double coeff = 1.0 - 2.0 * eps;\n            double bias = (double)k * eps;\n            double est = (rawResp - bias) / coeff;\n            est = max(0.0, est);\n            est = min(est, (double)k * M);\n            q.obs = est;\n\n            double varx = (double)k * eps * (1.0 - eps);\n            // include rounding noise ~0.25 and small stabilizer\n            double vart = (varx + 0.25) / (coeff * coeff) + 1e-3;\n            q.w = 1.0 / vart;\n        }\n\n        queries.push_back(std::move(q));\n        int qid = (int)queries.size() - 1;\n\n        // append intersection counts for every placement\n        for (int f = 0; f < M; f++) {\n            for (auto &p: fields[f].ps) {\n                int c = popcountAnd(p.bits, queries[qid].bits);\n                p.inter.push_back((int16_t)c);\n            }\n        }\n    }\n\n    // --- query constructors ---\n    vector<int> cellsRow(int r) const {\n        vector<int> v; v.reserve(N);\n        for (int c = 0; c < N; c++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsCol(int c) const {\n        vector<int> v; v.reserve(N);\n        for (int r = 0; r < N; r++) v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsBlock(int r0, int r1, int c0, int c1) const {\n        vector<int> v;\n        for (int r = r0; r < r1; r++)\n            for (int c = c0; c < c1; c++)\n                v.push_back(r*N + c);\n        return v;\n    }\n    vector<int> cellsChecker(bool parity) const {\n        vector<int> v;\n        for (int r = 0; r < N; r++)\n            for (int c = 0; c < N; c++)\n                if (((r+c)&1) == (parity?1:0)) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> cellsRandomFixedSize(int k) {\n        vector<int> all(N2);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n        all.resize(max(2, k));\n        sort(all.begin(), all.end());\n        all.erase(unique(all.begin(), all.end()), all.end());\n        if ((int)all.size() < 2) {\n            all.clear();\n            all.push_back(0);\n            all.push_back(1);\n        }\n        return all;\n    }\n\n    vector<uint64_t> bitsFromCells(const vector<int>& v) const {\n        vector<uint64_t> b(L, 0ULL);\n        for (int idx: v) bitSet(b, idx);\n        return b;\n    }\n\n    // perform a divination query\n    void doDivination(const vector<int>& cellIdx) {\n        if ((int)cellIdx.size() < 2) return;\n        if (!canSpendOps(1)) return;\n\n        vector<pair<int,int>> out;\n        out.reserve(cellIdx.size());\n        for (int idx: cellIdx) out.push_back({idx / N, idx % N});\n        int y = divineCells(out);\n\n        vector<uint64_t> b = bitsFromCells(cellIdx);\n        addQuery(cellIdx, b, (int)cellIdx.size(), y, false);\n    }\n\n    // drill a cell and add exact constraint-query\n    void doDrill(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (!canSpendOps(1)) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<int> cellIdx = {idx};\n        vector<uint64_t> b(L, 0ULL);\n        bitSet(b, idx);\n        addQuery(cellIdx, b, 1, v, true);\n    }\n\n    // --- SA inference ---\n    Solution runSA(const vector<int>* startIdx, int iters) {\n        int Q = (int)queries.size();\n        vector<double> obs(Q), w(Q);\n        for (int q = 0; q < Q; q++) { obs[q] = queries[q].obs; w[q] = queries[q].w; }\n\n        vector<int> idx(M, 0);\n        if (startIdx) idx = *startIdx;\n        else {\n            for (int f = 0; f < M; f++) {\n                uniform_int_distribution<int> dist(0, (int)fields[f].ps.size() - 1);\n                idx[f] = dist(rng);\n            }\n        }\n\n        vector<int> pred(Q, 0);\n        vector<double> err(Q, 0.0);\n        // initialize err = pred - obs\n        for (int q = 0; q < Q; q++) err[q] = -obs[q];\n        for (int f = 0; f < M; f++) {\n            auto &pl = fields[f].ps[idx[f]];\n            for (int q = 0; q < Q; q++) {\n                int c = pl.inter[q];\n                pred[q] += c;\n                err[q] += c;\n            }\n        }\n        double cost = 0;\n        for (int q = 0; q < Q; q++) cost += w[q] * err[q] * err[q];\n\n        vector<int> bestIdx = idx;\n        double bestCost = cost;\n\n        double T0 = 2.0, T1 = 0.05;\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        uniform_int_distribution<int> fieldDist(0, M-1);\n\n        for (int it = 0; it < iters; it++) {\n            double t = (double)it / max(1, iters - 1);\n            double T = T0 * pow(T1 / T0, t);\n\n            int f = fieldDist(rng);\n            int cur = idx[f];\n            int nxt = cur;\n\n            auto &ps = fields[f].ps;\n            if (!ps[cur].neigh.empty() && ur(rng) < 0.6) {\n                // local neighbor\n                uniform_int_distribution<int> nd(0, (int)ps[cur].neigh.size() - 1);\n                nxt = ps[cur].neigh[nd(rng)];\n            } else {\n                uniform_int_distribution<int> pd(0, (int)ps.size() - 1);\n                nxt = pd(rng);\n            }\n            if (nxt == cur) continue;\n\n            double delta = 0.0;\n            auto &oldP = ps[cur];\n            auto &newP = ps[nxt];\n\n            for (int q = 0; q < Q; q++) {\n                int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                if (d == 0) continue;\n                double e = err[q];\n                delta += w[q] * (2.0 * e * d + 1.0 * d * d);\n            }\n\n            if (delta <= 0.0 || ur(rng) < exp(-delta / T)) {\n                // accept\n                for (int q = 0; q < Q; q++) {\n                    int d = (int)newP.inter[q] - (int)oldP.inter[q];\n                    if (d == 0) continue;\n                    pred[q] += d;\n                    err[q] += d;\n                }\n                idx[f] = nxt;\n                cost += delta;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestIdx = idx;\n                }\n            }\n        }\n        return Solution{bestIdx, bestCost};\n    }\n\n    vector<Solution> sampleSolutions(int wantK) {\n        // SA restarts; keep best unique solutions\n        int restarts = 25;\n        int iters = 3500 + 30 * (int)queries.size();\n        iters = min(iters, 12000);\n\n        vector<Solution> sols;\n        sols.reserve(restarts);\n\n        // build a small pool of seeds from previous bests to stabilize (if any)\n        vector<vector<int>> seeds;\n        if (!sols.empty()) {\n            for (auto &s: sols) seeds.push_back(s.idx);\n        }\n\n        for (int r = 0; r < restarts; r++) {\n            vector<int> start;\n            bool useSeed = (!sols.empty() && (r % 5 == 0));\n            if (useSeed) {\n                start = sols[rng() % sols.size()].idx;\n                // random perturbation\n                for (int k = 0; k < 2; k++) {\n                    int f = rng() % M;\n                    int sz = (int)fields[f].ps.size();\n                    start[f] = rng() % sz;\n                }\n                auto res = runSA(&start, iters);\n                sols.push_back(std::move(res));\n            } else {\n                auto res = runSA(nullptr, iters);\n                sols.push_back(std::move(res));\n            }\n        }\n\n        sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b){ return a.cost < b.cost; });\n\n        unordered_set<uint64_t> seen;\n        vector<Solution> out;\n        for (auto &s: sols) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int x: s.idx) h = splitmix64(h ^ (uint64_t)x + 0x9e3779b97f4a7c15ULL);\n            if (seen.insert(h).second) out.push_back(s);\n            if ((int)out.size() >= wantK) break;\n        }\n        if (out.empty()) out.push_back(sols[0]);\n        return out;\n    }\n\n    // compute per-cell probability of being covered among given solutions\n    vector<double> computeCellProb(const vector<Solution>& sols) {\n        vector<int> cnt(N2, 0);\n        for (auto &s: sols) {\n            vector<uint64_t> uni(L, 0ULL);\n            for (int f = 0; f < M; f++) {\n                auto &pb = fields[f].ps[s.idx[f]].bits;\n                for (int t = 0; t < L; t++) uni[t] |= pb[t];\n            }\n            for (int idx = 0; idx < N2; idx++) {\n                if (bitGet(uni, idx)) cnt[idx]++;\n            }\n        }\n        vector<double> p(N2, 0.0);\n        for (int i = 0; i < N2; i++) p[i] = (double)cnt[i] / (double)sols.size();\n        // enforce drilled constraints (for decisions)\n        for (int i = 0; i < N2; i++) {\n            if (drilledVal[i] != -1) p[i] = (drilledVal[i] > 0) ? 1.0 : 0.0;\n        }\n        return p;\n    }\n\n    vector<pair<int,int>> buildAnswerFromProb(const vector<double>& p) const {\n        vector<pair<int,int>> ans;\n        ans.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            bool oil = (p[idx] >= 0.5);\n            if (drilledVal[idx] != -1) oil = (drilledVal[idx] > 0);\n            if (oil) ans.push_back({idx / N, idx % N});\n        }\n        return ans;\n    }\n\n    // --- main solve routine ---\n    void solve() {\n        // initial divinations (stop early if we must reserve operations)\n        // rows/cols\n        for (int i = 0; i < N; i++) doDivination(cellsRow(i));\n        for (int j = 0; j < N; j++) doDivination(cellsCol(j));\n\n        // blocks\n        int B = (N >= 18) ? 4 : (N >= 14) ? 3 : 2;\n        int step = (N + B - 1) / B;\n        for (int bi = 0; bi < B; bi++) {\n            for (int bj = 0; bj < B; bj++) {\n                int r0 = bi * step, r1 = min(N, (bi + 1) * step);\n                int c0 = bj * step, c1 = min(N, (bj + 1) * step);\n                auto v = cellsBlock(r0, r1, c0, c1);\n                if ((int)v.size() >= 2) doDivination(v);\n            }\n        }\n\n        // checkerboards\n        doDivination(cellsChecker(false));\n        doDivination(cellsChecker(true));\n\n        // random large subsets\n        int randQ = (N >= 16 ? 18 : 14);\n        for (int t = 0; t < randQ; t++) {\n            int k = (t % 2 == 0) ? (N2 / 2) : (N2 / 3);\n            doDivination(cellsRandomFixedSize(k));\n        }\n\n        // iterative: SA -> probabilities -> drill uncertain\n        int maxRounds = 6;\n        int totalDrillBudget = (N >= 16 ? 70 : 55);\n        int drilledThisPhase = 0;\n\n        for (int round = 0; round < maxRounds; round++) {\n            int wantK = 25;\n            auto sols = sampleSolutions(wantK);\n            auto prob = computeCellProb(sols);\n\n            // collect uncertain cells\n            const double pLow = 0.05, pHigh = 0.95;\n            vector<pair<double,int>> cand;\n            cand.reserve(N2);\n            for (int idx = 0; idx < N2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                double p = prob[idx];\n                if (pLow < p && p < pHigh) {\n                    cand.push_back({abs(p - 0.5), idx});\n                }\n            }\n            sort(cand.begin(), cand.end());\n\n            if (cand.empty()) {\n                // extra validation drills (small)\n                bool mismatch = false;\n                vector<pair<double,int>> zeroCand, oneCand;\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    double p = prob[idx];\n                    if (p <= pLow) zeroCand.push_back({-p, idx}); // closer to boundary first\n                    else if (p >= pHigh) oneCand.push_back({p, idx}); // smaller p first\n                }\n                sort(zeroCand.begin(), zeroCand.end());\n                sort(oneCand.begin(), oneCand.end());\n\n                int checks = 0;\n                for (int t = 0; t < (int)zeroCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = zeroCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] > 0) mismatch = true;\n                }\n                checks = 0;\n                for (int t = 0; t < (int)oneCand.size() && checks < 4; t++) {\n                    if (!canSpendOps(1) || drilledThisPhase >= totalDrillBudget) break;\n                    int idx = oneCand[t].second;\n                    doDrill(idx);\n                    drilledThisPhase++;\n                    checks++;\n                    if (drilledVal[idx] == 0) mismatch = true;\n                }\n                if (mismatch) continue;\n\n                // attempt answer (keeping fallback possible)\n                if (canSpendOps(1)) {\n                    auto ans = buildAnswerFromProb(prob);\n                    int ok = answerCells(ans);\n                    if (ok == 1) return;\n                    // if wrong, break to fallback\n                    break;\n                } else {\n                    break;\n                }\n            } else {\n                // drill the most uncertain cells (batch)\n                int batch = min(10, (int)cand.size());\n                for (int t = 0; t < batch; t++) {\n                    if (drilledThisPhase >= totalDrillBudget) break;\n                    if (!canSpendOps(1)) break;\n                    doDrill(cand[t].second);\n                    drilledThisPhase++;\n                }\n            }\n        }\n\n        // fallback: drill everything remaining, answer exactly\n        vector<pair<int,int>> oilCells;\n        oilCells.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] == -1) doDrill(idx);\n            if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n        }\n        (void)answerCells(oilCells);\n        return;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    double eps;\n    cin >> N >> M >> eps;\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; k++) {\n        int d;\n        cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; t++) {\n            int i, j;\n            cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    Solver solver(N, M, eps);\n    solver.buildPlacements(shapes);\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF = (1LL << 60);\n\nstatic inline vector<int> make_prefix(const vector<int>& h) {\n    int N = (int)h.size();\n    vector<int> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i + 1] = pref[i] + h[i];\n    return pref;\n}\n\n// mismatch cost (true objective piece) + tiny tie-breaker (never overrides 2000)\nstatic inline long long boundary_cost(int p, int bidx,\n                                      const vector<int>* prevPref,\n                                      const vector<int>* nextPref) {\n    long long cost = 0;\n    int tgt = p;\n    int cnt = 0;\n    if (prevPref) {\n        cost += (p == (*prevPref)[bidx]) ? 0 : 2000;\n        tgt += (*prevPref)[bidx];\n        cnt++;\n    }\n    if (nextPref) {\n        cost += (p == (*nextPref)[bidx]) ? 0 : 2000;\n        tgt += (*nextPref)[bidx];\n        cnt++;\n    }\n    if (cnt > 0) {\n        tgt /= (cnt + 1);\n        cost += llabs((long long)p - tgt); // tie-breaker (<1000)\n    }\n    return cost;\n}\n\n// Check if a given layout (heights) can satisfy all demands with zero shortage\n// by optimal relabeling (sort heights and compare to need[]).\nstatic inline bool can_fit_zero_shortage(const vector<int>& h, const vector<int>& need_sorted) {\n    vector<int> hs = h;\n    sort(hs.begin(), hs.end());\n    for (int k = 0; k < (int)hs.size(); k++) {\n        if (hs[k] < need_sorted[k]) return false;\n    }\n    return true;\n}\n\n// Feasible day DP: choose h[k] >= need[k] (position-wise), sum=1000 minimizing boundary mismatches to prev/next.\nstatic vector<int> optimize_feasible(const vector<int>& need,\n                                    const vector<int>* prevPref,\n                                    const vector<int>* nextPref) {\n    int N = (int)need.size();\n    static long long dp[W + 1], ndp[W + 1];\n    static long long bestVal[W + 1];\n    static int bestIdx[W + 1];\n    static int16_t par[55][W + 1]; // par[k+1][p2] = pPrev\n\n    vector<int> suf(N + 1, 0);\n    for (int i = N - 1; i >= 0; i--) suf[i] = suf[i + 1] + need[i];\n\n    for (int p = 0; p <= W; p++) dp[p] = INF;\n    dp[0] = 0;\n    for (int k = 0; k <= N; k++) for (int p = 0; p <= W; p++) par[k][p] = -1;\n\n    for (int k = 0; k < N; k++) {\n        bestVal[0] = dp[0];\n        bestIdx[0] = 0;\n        for (int p = 1; p <= W; p++) {\n            if (dp[p] < bestVal[p - 1]) {\n                bestVal[p] = dp[p];\n                bestIdx[p] = p;\n            } else {\n                bestVal[p] = bestVal[p - 1];\n                bestIdx[p] = bestIdx[p - 1];\n            }\n        }\n\n        for (int p = 0; p <= W; p++) ndp[p] = INF;\n\n        for (int p2 = 0; p2 <= W; p2++) {\n            if (W - p2 < suf[k + 1]) continue;\n            int lim = p2 - need[k];\n            if (lim < 0) continue;\n            long long base = bestVal[lim];\n            if (base >= INF / 2) continue;\n\n            long long cost = base;\n            if (k < N - 1) cost += boundary_cost(p2, k + 1, prevPref, nextPref);\n\n            if (cost < ndp[p2]) {\n                ndp[p2] = cost;\n                par[k + 1][p2] = (int16_t)bestIdx[lim];\n            }\n        }\n\n        for (int p = 0; p <= W; p++) dp[p] = ndp[p];\n    }\n\n    int p = W;\n    if (dp[p] >= INF / 2) {\n        // fallback: need + slack\n        vector<int> h = need;\n        int s = accumulate(h.begin(), h.end(), 0);\n        h.back() += (W - s);\n        return h;\n    }\n\n    vector<int> h(N, 1);\n    for (int k = N - 1; k >= 0; k--) {\n        int pPrev = par[k + 1][p];\n        if (pPrev < 0) pPrev = max(0, p - need[k]);\n        h[k] = p - pPrev;\n        p = pPrev;\n    }\n    int sumH = accumulate(h.begin(), h.end(), 0);\n    h.back() += (W - sumH);\n    if (h.back() <= 0) h.back() = 1;\n    return h;\n}\n\n// Infeasible day DP: start from need (ceil(a/1000)), must decrement T=sumNeed-1000 units.\n// This DP assumes the same ordering as need[] (as before); later we can permute heights without changing shortage.\nstatic vector<int> optimize_infeasible(const vector<int>& a,\n                                      const vector<int>& need,\n                                      const vector<int>* prevPref,\n                                      const vector<int>* nextPref) {\n    int N = (int)need.size();\n    int sumNeed = accumulate(need.begin(), need.end(), 0);\n    int T = sumNeed - W;\n\n    vector<int> basePref(N + 1, 0);\n    for (int i = 0; i < N; i++) basePref[i + 1] = basePref[i] + need[i];\n\n    vector<int> firstCost(N, 0);\n    for (int k = 0; k < N; k++) {\n        int r = a[k] % W;\n        int deltaArea = (r == 0 ? W : r); // first decrement adds this shortage area\n        firstCost[k] = 100 * deltaArea;\n    }\n\n    static long long dp[55], ndp[55];\n    static int8_t parX[55][55];\n    static int8_t parDec[55][55];\n\n    for (int x = 0; x <= T; x++) dp[x] = INF;\n    dp[0] = 0;\n    for (int i = 0; i <= N; i++) for (int x = 0; x <= T; x++) parX[i][x] = parDec[i][x] = -1;\n\n    for (int k = 0; k < N; k++) {\n        for (int x = 0; x <= T; x++) ndp[x] = INF;\n\n        for (int x = 0; x <= T; x++) if (dp[x] < INF / 2) {\n            int maxDec = min(need[k] - 1, T - x);\n            for (int dec = 0; dec <= maxDec; dec++) {\n                int x2 = x + dec;\n                long long add = 0;\n                if (dec >= 1) {\n                    add += firstCost[k];\n                    if (dec >= 2) add += 100000LL * (dec - 1); // each further decrement adds 1000 shortage => 100000\n                }\n                int pos = basePref[k + 1] - x2;\n                long long cost = dp[x] + add;\n                if (k < N - 1) cost += boundary_cost(pos, k + 1, prevPref, nextPref);\n\n                if (cost < ndp[x2]) {\n                    ndp[x2] = cost;\n                    parX[k + 1][x2] = (int8_t)x;\n                    parDec[k + 1][x2] = (int8_t)dec;\n                }\n            }\n        }\n        for (int x = 0; x <= T; x++) dp[x] = ndp[x];\n    }\n\n    int x = T;\n    if (dp[x] >= INF / 2) {\n        // fallback greedy decrement\n        vector<int> h = need;\n        int excess = T;\n        vector<pair<int,int>> cand;\n        for (int k = 0; k < N; k++) if (h[k] > 1) cand.push_back({firstCost[k], k});\n        sort(cand.begin(), cand.end());\n        int idx = 0;\n        while (excess > 0 && !cand.empty()) {\n            int k = cand[min(idx, (int)cand.size()-1)].second;\n            if (h[k] > 1) { h[k]--; excess--; }\n            else idx++;\n        }\n        int sumH = accumulate(h.begin(), h.end(), 0);\n        h.back() += (W - sumH);\n        if (h.back() <= 0) h.back() = 1;\n        return h;\n    }\n\n    vector<int> h(N, 1);\n    vector<int> decs(N, 0);\n    for (int k = N - 1; k >= 0; k--) {\n        int px = parX[k + 1][x];\n        int dec = parDec[k + 1][x];\n        if (px < 0) { px = 0; dec = 0; }\n        decs[k] = dec;\n        x = px;\n    }\n    for (int k = 0; k < N; k++) h[k] = need[k] - decs[k];\n\n    int sumH = accumulate(h.begin(), h.end(), 0);\n    h.back() += (W - sumH);\n    if (h.back() <= 0) h.back() = 1;\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Win, D, N;\n    cin >> Win >> D >> N;\n    (void)Win;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) for (int k = 0; k < N; k++) cin >> a[d][k];\n\n    vector<vector<int>> need(D, vector<int>(N));\n    vector<int> sumNeed(D, 0);\n    for (int d = 0; d < D; d++) {\n        int s = 0;\n        for (int k = 0; k < N; k++) {\n            need[d][k] = max(1, (a[d][k] + W - 1) / W);\n            s += need[d][k];\n        }\n        sumNeed[d] = s;\n    }\n\n    // Step 1: forward construction with \"keep previous layout if it can fit with zero shortage\"\n    vector<vector<int>> h(D, vector<int>(N, 1));\n\n    // day 0 initialization\n    if (sumNeed[0] <= W) {\n        h[0] = need[0];\n        h[0].back() += (W - sumNeed[0]);\n    } else {\n        h[0] = optimize_infeasible(a[0], need[0], nullptr, nullptr);\n    }\n    // safety\n    {\n        int s = accumulate(h[0].begin(), h[0].end(), 0);\n        h[0].back() += (W - s);\n        if (h[0].back() <= 0) h[0].back() = 1;\n    }\n\n    for (int d = 1; d < D; d++) {\n        if (sumNeed[d] <= W && can_fit_zero_shortage(h[d - 1], need[d])) {\n            h[d] = h[d - 1]; // exact keep => L_d = 0\n            continue;\n        }\n\n        vector<int> prevPref = make_prefix(h[d - 1]);\n        if (sumNeed[d] <= W) {\n            // prev-only DP (more conservative than prev+next, tends to reduce changes)\n            h[d] = optimize_feasible(need[d], &prevPref, nullptr);\n        } else {\n            h[d] = optimize_infeasible(a[d], need[d], &prevPref, nullptr);\n        }\n        int s = accumulate(h[d].begin(), h[d].end(), 0);\n        h[d].back() += (W - s);\n        if (h[d].back() <= 0) h[d].back() = 1;\n    }\n\n    // Step 2: a few smoothing iterations (coordinate descent style) to also consider next day\n    const int ITER = 6;\n    for (int it = 0; it < ITER; it++) {\n        for (int d = 0; d < D; d++) {\n            vector<int> prevPref, nextPref;\n            const vector<int>* pPrev = nullptr;\n            const vector<int>* pNext = nullptr;\n            if (d > 0) { prevPref = make_prefix(h[d - 1]); pPrev = &prevPref; }\n            if (d + 1 < D) { nextPref = make_prefix(h[d + 1]); pNext = &nextPref; }\n\n            // Keep if possible (helps avoid needless changes)\n            if (d > 0 && sumNeed[d] <= W && can_fit_zero_shortage(h[d - 1], need[d])) continue;\n\n            if (sumNeed[d] <= W) h[d] = optimize_feasible(need[d], pPrev, pNext);\n            else h[d] = optimize_infeasible(a[d], need[d], pPrev, pNext);\n\n            int s = accumulate(h[d].begin(), h[d].end(), 0);\n            h[d].back() += (W - s);\n            if (h[d].back() <= 0) h[d].back() = 1;\n        }\n    }\n\n    // Step 3: adjacent-swap hillclimb to reduce exact partition mismatch cost\n    // For full-width horizontal stripes: edge cost is 2000 * (#boundaries with different y positions).\n    vector<vector<int>> pref(D, vector<int>(N + 1, 0));\n    for (int d = 0; d < D; d++) pref[d] = make_prefix(h[d]);\n\n    auto mismatch = [&](int d1, int d2, int b) -> int {\n        return pref[d1][b] != pref[d2][b];\n    };\n\n    auto start = chrono::steady_clock::now();\n    int sweeps = 0;\n    while (true) {\n        bool improved = false;\n        sweeps++;\n\n        // time guard (~2.8 sec)\n        if (sweeps % 50 == 0) {\n            auto now = chrono::steady_clock::now();\n            double sec = chrono::duration<double>(now - start).count();\n            if (sec > 2.8) break;\n        }\n\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < N - 1; i++) {\n                int b = i + 1;\n                int pOld = pref[d][b];\n                int pNew = pref[d][i] + h[d][i + 1]; // boundary after swap\n\n                int delta = 0;\n                if (d > 0) delta += ( (pNew != pref[d - 1][b]) - (pOld != pref[d - 1][b]) );\n                if (d + 1 < D) delta += ( (pref[d + 1][b] != pNew) - (pref[d + 1][b] != pOld) );\n\n                if (delta < 0) {\n                    // apply swap\n                    swap(h[d][i], h[d][i + 1]);\n                    pref[d][b] = pNew;\n                    improved = true;\n                }\n            }\n        }\n        if (!improved) break;\n    }\n\n    // Output: build rectangles in physical order, then assign demands to stripes by sorting stripe heights.\n    for (int d = 0; d < D; d++) {\n        vector<array<int,4>> stripeRect(N);\n        int y = 0;\n        for (int s = 0; s < N; s++) {\n            int y2 = y + h[d][s];\n            if (s == N - 1) y2 = W; // force exact end\n            stripeRect[s] = {y, 0, y2, W};\n            y = y2;\n        }\n\n        vector<int> idx(N);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int i, int j) {\n            return h[d][i] < h[d][j];\n        });\n\n        // demands are sorted by k already; assign smallest demand to smallest stripe\n        for (int k = 0; k < N; k++) {\n            auto r = stripeRect[idx[k]];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << \"\\n\";\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline uint32_t addmod(uint32_t a, uint32_t b) {\n    uint32_t s = a + b;\n    if (s >= MOD) s -= MOD;\n    return s;\n}\nstatic inline uint32_t negmod(uint32_t a) {\n    return a ? (MOD - a) : 0u;\n}\n\nstruct Action {\n    uint8_t m, p, q;\n    uint8_t idx[9];   // affected cell indices 0..80\n    uint32_t val[9];  // added values mod MOD\n};\n\nstruct DeltaBuf {\n    array<uint32_t, 81> delta{};\n    array<int, 81> vis{};\n    int iter = 1;\n    uint8_t cells[18];\n    int cnt = 0;\n\n    inline void clear() {\n        iter++;\n        if (iter == INT_MAX) { // very unlikely, but safe\n            iter = 1;\n            vis.fill(0);\n        }\n        cnt = 0;\n    }\n    inline void addCell(uint8_t c, uint32_t dv) {\n        if (dv == 0) return;\n        if (vis[c] != iter) {\n            vis[c] = iter;\n            delta[c] = dv;\n            cells[cnt++] = c;\n        } else {\n            delta[c] = addmod(delta[c], dv);\n        }\n    }\n};\n\nstatic inline int64_t add_gain_only(const Action &a, const array<uint32_t,81> &res) {\n    int64_t d = 0;\n    for (int k = 0; k < 9; k++) {\n        uint8_t c = a.idx[k];\n        uint32_t r = res[c];\n        uint32_t nr = r + a.val[k];\n        if (nr >= MOD) nr -= MOD;\n        d += (int64_t)nr - (int64_t)r;\n    }\n    return d;\n}\n\nstatic inline int64_t compute_change(int oldId, int newId,\n                                    const vector<Action> &actions,\n                                    const array<uint32_t,81> &res,\n                                    DeltaBuf &buf) {\n    buf.clear();\n    if (oldId != -1) {\n        const auto &a = actions[oldId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], negmod(a.val[k]));\n    }\n    if (newId != -1) {\n        const auto &a = actions[newId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], a.val[k]);\n    }\n    int64_t dscore = 0;\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        dscore += (int64_t)nr - (int64_t)r;\n    }\n    return dscore;\n}\n\nstatic inline void apply_change(const DeltaBuf &buf, array<uint32_t,81> &res) {\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        res[c] = nr;\n    }\n}\n\nstatic inline int64_t score_of(const array<uint32_t,81> &res) {\n    int64_t s = 0;\n    for (uint32_t v : res) s += v;\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K; // N=9,M=20,K=81\n\n    array<uint32_t,81> a0{};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        uint64_t x; cin >> x;\n        a0[i*N + j] = (uint32_t)(x % MOD);\n    }\n\n    vector<array<uint32_t,9>> stamps(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n            uint64_t x; cin >> x;\n            stamps[m][i*3 + j] = (uint32_t)(x % MOD);\n        }\n    }\n\n    // Precompute actions\n    vector<Action> actions;\n    actions.reserve(M * (N-2) * (N-2));\n    // mapping: stamp m, pos (p*7+q) -> action id\n    array<array<int, 49>, 20> idOf{};\n    for (int m = 0; m < M; m++) for (int pos = 0; pos < 49; pos++) idOf[m][pos] = -1;\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action act;\n                act.m = (uint8_t)m;\n                act.p = (uint8_t)p;\n                act.q = (uint8_t)q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n                    int bi = p + i, bj = q + j;\n                    act.idx[t] = (uint8_t)(bi * N + bj);\n                    act.val[t] = stamps[m][i*3 + j];\n                    t++;\n                }\n                int id = (int)actions.size();\n                actions.push_back(act);\n                int pos = p * 7 + q;\n                idOf[m][pos] = id;\n            }\n        }\n    }\n    const int A = (int)actions.size(); // 980\n\n    // Seed RNG input-dependent\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 81; i++) seed = seed * 1000003ULL + a0[i];\n    XorShift64 rng(seed);\n\n    // exp lookup for x in [-20,0]\n    static vector<double> expTab;\n    if (expTab.empty()) {\n        const int STEPS = 8192;\n        expTab.resize(STEPS + 1);\n        for (int i = 0; i <= STEPS; i++) {\n            double x = -20.0 * (double)i / (double)STEPS;\n            expTab[i] = exp(x);\n        }\n    }\n    auto exp_lookup = [&](double x)->double { // x in [-20,0]\n        if (x <= -20.0) return 0.0;\n        if (x >= 0.0) return 1.0;\n        const int STEPS = (int)expTab.size() - 1;\n        int idx = (int)llround((-x) * (double)STEPS / 20.0);\n        if (idx < 0) idx = 0;\n        if (idx > STEPS) idx = STEPS;\n        return expTab[idx];\n    };\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n\n    auto elapsedSec = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    auto best_stamp_for_pos = [&](int pos, const array<uint32_t,81> &res)->int {\n        int bestId = -1;\n        int64_t bestGain = LLONG_MIN;\n        for (int m = 0; m < M; m++) {\n            int id = idOf[m][pos];\n            int64_t g = add_gain_only(actions[id], res);\n            if (g > bestGain) {\n                bestGain = g;\n                bestId = id;\n            }\n        }\n        return bestId;\n    };\n\n    // Build solution from ops\n    auto rebuild = [&](const vector<int> &ops, array<uint32_t,81> &res)->int64_t {\n        res = a0;\n        for (int id : ops) {\n            if (id == -1) continue;\n            const auto &a = actions[id];\n            for (int k = 0; k < 9; k++) {\n                uint8_t c = a.idx[k];\n                uint32_t nr = res[c] + a.val[k];\n                if (nr >= MOD) nr -= MOD;\n                res[c] = nr;\n            }\n        }\n        return score_of(res);\n    };\n\n    // One run: init then SA+LNS, return best\n    vector<int> globalBestOps(K, -1);\n    int64_t globalBestScore = score_of(a0);\n\n    DeltaBuf buf;\n\n    auto do_run = [&](int mode, double endTimeSec) {\n        // mode 0: greedy with small randomness\n        // mode 1: randomized by position (choose pos random, best stamp for that pos wrt current)\n        vector<int> ops(K, -1);\n        array<uint32_t,81> res = a0;\n        int64_t score = score_of(res);\n\n        if (mode == 0) {\n            // Greedy fill, but sometimes pick among top few to diversify\n            for (int slot = 0; slot < K; slot++) {\n                int best1 = -1, best2 = -1, best3 = -1;\n                int64_t g1 = 0, g2 = 0, g3 = 0;\n                for (int id = 0; id < A; id++) {\n                    int64_t g = add_gain_only(actions[id], res);\n                    if (g > g1) {\n                        best3 = best2; g3 = g2;\n                        best2 = best1; g2 = g1;\n                        best1 = id;    g1 = g;\n                    } else if (g > g2) {\n                        best3 = best2; g3 = g2;\n                        best2 = id;    g2 = g;\n                    } else if (g > g3) {\n                        best3 = id;    g3 = g;\n                    }\n                }\n                if (best1 == -1 || g1 <= 0) break;\n                int pick = best1;\n                // 15%: pick best2/3 if close\n                if (rng.nextInt(100) < 15) {\n                    int r = rng.nextInt(3);\n                    if (r == 1 && best2 != -1) pick = best2;\n                    if (r == 2 && best3 != -1) pick = best3;\n                }\n                ops[slot] = pick;\n                const auto &a = actions[pick];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n                score += add_gain_only(a, res); // WRONG if used after applying; avoid; keep score by recomputing delta before apply\n                // Fix: we won't use this broken score update; recompute after greedy loop.\n                // (We keep this line harmless by overwriting score below.)\n            }\n            score = score_of(res);\n        } else {\n            // Randomized position-based construction\n            for (int slot = 0; slot < K; slot++) {\n                int pos = rng.nextInt(49);\n                int id = best_stamp_for_pos(pos, res);\n                // small chance to take random stamp instead\n                if (rng.nextInt(100) < 10) {\n                    int m = rng.nextInt(M);\n                    id = idOf[m][pos];\n                }\n                ops[slot] = id;\n                const auto &a = actions[id];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n            }\n            score = score_of(res);\n        }\n\n        // track local best\n        vector<int> bestOps = ops;\n        int64_t bestScore = score;\n        array<uint32_t,81> bestRes = res;\n\n        // SA parameters\n        const double T0 = 2.0e9;\n        const double T1 = 2.0e6;\n        const double logRatio = log(T1 / T0);\n\n        double lastCheck = elapsedSec();\n        double T = T0;\n        uint64_t iters = 0;\n\n        auto accept_move = [&](int64_t d)->bool {\n            if (d >= 0) return true;\n            double x = (double)d / T; // negative\n            double prob = exp_lookup(x);\n            return rng.nextDouble() < prob;\n        };\n\n        // SA loop\n        while (true) {\n            iters++;\n\n            if ((iters & 2047ull) == 0) {\n                double e = elapsedSec();\n                if (e >= endTimeSec) break;\n                double prog = (e - lastCheck) / max(1e-9, (endTimeSec - lastCheck)); // not great; use global progress instead\n                (void)prog;\n                double globalProg = min(1.0, e / endTimeSec);\n                T = T0 * exp(logRatio * globalProg);\n            }\n\n            int moveType = rng.nextInt(100);\n            if (moveType < 70) {\n                // 1-slot replace\n                int slot = rng.nextInt(K);\n                int oldId = ops[slot];\n\n                int newId = -1;\n                int r = rng.nextInt(100);\n\n                if (r < 10) {\n                    newId = -1;\n                } else if (r < 40) {\n                    // random action\n                    newId = rng.nextInt(A);\n                } else if (r < 65) {\n                    // best stamp for random pos\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1 && r < 85) {\n                    // same position, best stamp\n                    int pos = actions[oldId].p * 7 + actions[oldId].q;\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1) {\n                    // same stamp, random position\n                    int m = actions[oldId].m;\n                    int pos = rng.nextInt(49);\n                    newId = idOf[m][pos];\n                } else {\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                }\n\n                if (newId == oldId) continue;\n\n                int64_t d = compute_change(oldId, newId, actions, res, buf);\n                if (accept_move(d)) {\n                    apply_change(buf, res);\n                    score += d;\n                    ops[slot] = newId;\n\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else if (moveType < 90) {\n                // 2-slot replace\n                int s1 = rng.nextInt(K);\n                int s2 = rng.nextInt(K);\n                if (s1 == s2) continue;\n                int old1 = ops[s1], old2 = ops[s2];\n\n                int new1, new2;\n                // propose using strong candidates sometimes\n                auto propose = [&](int oldId)->int {\n                    int rr = rng.nextInt(100);\n                    if (rr < 10) return -1;\n                    if (rr < 35) return rng.nextInt(A);\n                    if (rr < 70) {\n                        int pos = rng.nextInt(49);\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    if (oldId != -1) {\n                        int pos = actions[oldId].p * 7 + actions[oldId].q;\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    int pos = rng.nextInt(49);\n                    return best_stamp_for_pos(pos, res);\n                };\n                new1 = propose(old1);\n                new2 = propose(old2);\n                if (new1 == old1 && new2 == old2) continue;\n\n                // apply combined by sequential compute in a temp copy (cheap, 81 cells)\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // change slot1\n                int64_t d1 = compute_change(old1, new1, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d1;\n                // change slot2 (note: use updated tmpRes)\n                int64_t d2 = compute_change(old2, new2, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d2;\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    res = tmpRes;\n                    score = tmpScore;\n                    ops[s1] = new1;\n                    ops[s2] = new2;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else {\n                // LNS: remove t random slots, then greedily refill\n                int t = 6 + rng.nextInt(7); // 6..12\n                vector<int> idx(K);\n                iota(idx.begin(), idx.end(), 0);\n                for (int i = 0; i < t; i++) {\n                    int j = i + rng.nextInt(K - i);\n                    swap(idx[i], idx[j]);\n                }\n                idx.resize(t);\n\n                vector<int> tmpOps = ops;\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // remove chosen slots\n                for (int slot : idx) {\n                    int oldId = tmpOps[slot];\n                    if (oldId == -1) continue;\n                    int64_t d = compute_change(oldId, -1, actions, tmpRes, buf);\n                    apply_change(buf, tmpRes);\n                    tmpScore += d;\n                    tmpOps[slot] = -1;\n                }\n\n                // greedy refill chosen slots (leave empty if bestGain <= 0 most of the time)\n                for (int slot : idx) {\n                    int bestId = -1;\n                    int64_t bestG = LLONG_MIN;\n\n                    // Use a mix: try best over all actions, but we can speed by also trying best-per-pos sometimes.\n                    // Since A=980 small, full scan is fine here.\n                    for (int id = 0; id < A; id++) {\n                        int64_t g = add_gain_only(actions[id], tmpRes);\n                        if (g > bestG) { bestG = g; bestId = id; }\n                    }\n\n                    if (bestId != -1) {\n                        bool take = (bestG > 0) || (rng.nextInt(100) < 10); // 10% take even if <=0\n                        if (take) {\n                            const auto &a = actions[bestId];\n                            for (int k = 0; k < 9; k++) {\n                                uint8_t c = a.idx[k];\n                                uint32_t nr = tmpRes[c] + a.val[k];\n                                if (nr >= MOD) nr -= MOD;\n                                tmpRes[c] = nr;\n                            }\n                            tmpOps[slot] = bestId;\n                            // update tmpScore by exact delta\n                            // (use add_gain_only on original res would be wrong; recompute via direct diff)\n                            // easiest: recompute score delta for 9 cells:\n                            // but we already updated tmpRes; so compute delta by subtracting old via storing old values:\n                            // keep it simple: compute after all refills (81 cells only).\n                        }\n                    }\n                }\n                tmpScore = score_of(tmpRes);\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    ops.swap(tmpOps);\n                    res = tmpRes;\n                    score = tmpScore;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            }\n        }\n\n        // Final local refinement: repeat 1-opt until no improvement or time\n        ops = bestOps;\n        score = rebuild(ops, res);\n        bool any = true;\n        while (any && elapsedSec() < endTimeSec) {\n            any = false;\n            vector<int> order(K);\n            iota(order.begin(), order.end(), 0);\n            // lightweight shuffle\n            for (int i = 0; i < K; i++) swap(order[i], order[rng.nextInt(K)]);\n\n            for (int t = 0; t < K; t++) {\n                if (elapsedSec() >= endTimeSec) break;\n                int slot = order[t];\n                int oldId = ops[slot];\n\n                int bestNew = oldId;\n                int64_t bestD = 0;\n                DeltaBuf bestBufLocal;\n\n                // try empty\n                {\n                    int64_t d = compute_change(oldId, -1, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = -1;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                // try all actions\n                for (int id = 0; id < A; id++) {\n                    if (id == oldId) continue;\n                    int64_t d = compute_change(oldId, id, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = id;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                if (bestNew != oldId) {\n                    apply_change(bestBufLocal, res);\n                    score += bestD;\n                    ops[slot] = bestNew;\n                    any = true;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                    }\n                }\n            }\n        }\n\n        if (bestScore > globalBestScore) {\n            globalBestScore = bestScore;\n            globalBestOps = bestOps;\n        }\n    };\n\n    // Time budgeting: 2 runs + final polishing built-in each run\n    // Run 1: greedy-ish init\n    do_run(0, min(TL, 1.30));\n    // Run 2: randomized init, use remaining time\n    do_run(1, TL);\n\n    // Output\n    vector<tuple<int,int,int>> out;\n    out.reserve(K);\n    for (int id : globalBestOps) {\n        if (id == -1) continue;\n        const auto &a = actions[id];\n        out.emplace_back((int)a.m, (int)a.p, (int)a.q);\n    }\n    cout << out.size() << \"\\n\";\n    for (auto &[m,p,q] : out) {\n        cout << m << \" \" << p << \" \" << q << \"\\n\";\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 5;\nstatic const int MAX_TURNS = 10000;\n\nstruct Solver {\n    int A[N][N];\n    int origRow[N*N], origIdx[N*N];\n\n    // grid: container id or -1\n    int grid[N][N];\n\n    // id position on grid; (-1,-1) if not on grid (carried or dispatched)\n    int posR[N*N], posC[N*N];\n\n    // receiving progress\n    int spawned[N]; // number already spawned per row (0..5)\n\n    // dispatch progress as mask: bit k means (rowGroup*5 + k) dispatched\n    int dispMask[N];\n    int dispatchedCount = 0;\n\n    struct Crane {\n        int r=0, c=0;\n        bool alive=true;\n        bool holding=false;\n        int held=-1;\n        bool large=false;\n    };\n    Crane cranes[N]; // 0 large, 1..4 small\n\n    deque<char> plan0; // large crane action queue\n    vector<string> out;\n    int turn = 0;\n\n    // progress / safety\n    int lastDispatchedCount = 0;\n    int noProgressTurns = 0;\n    bool panic = false;\n\n    // parameters\n    static constexpr int STUCK_LIMIT = 250;     // enter panic if no dispatch this many turns\n    static constexpr int STORAGE_TIGHT = 1;     // if <= this many empty storage cells, allow out-of-order dispatch\n\n    Solver(const vector<vector<int>>& Ain) : out(N, \"\") {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            A[i][j] = Ain[i][j];\n            origRow[A[i][j]] = i;\n            origIdx[A[i][j]] = j;\n        }\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) grid[i][j] = -1;\n        for(int id=0;id<N*N;id++){\n            posR[id] = posC[id] = -1;\n        }\n        for(int i=0;i<N;i++){\n            spawned[i] = 0;\n            dispMask[i] = 0;\n        }\n\n        for(int i=0;i<N;i++){\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].alive = true;\n            cranes[i].holding = false;\n            cranes[i].held = -1;\n            cranes[i].large = (i==0);\n        }\n    }\n\n    int expectedIndex(int t) const {\n        for(int k=0;k<N;k++){\n            if(((dispMask[t] >> k) & 1) == 0) return k;\n        }\n        return N;\n    }\n\n    int expectedId(int t) const {\n        int k = expectedIndex(t);\n        if(k>=N) return -1;\n        return N*t + k;\n    }\n\n    int invCostIfDispatch(int id) const {\n        int t = id / N;\n        int idx = id % N;\n        int cost = 0;\n        for(int k=0;k<idx;k++){\n            if(((dispMask[t] >> k) & 1) == 0) cost++;\n        }\n        return cost;\n    }\n\n    bool holdingCraneAtCell(int r, int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==r && cranes[k].c==c && cranes[k].holding) return true;\n        }\n        return false;\n    }\n    bool craneAtCell(int r, int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n\n    void spawnPhase(){\n        for(int r=0;r<N;r++){\n            if(spawned[r] >= N) continue;\n            if(grid[r][0] != -1) continue;\n            if(holdingCraneAtCell(r,0)) continue;\n            int id = A[r][spawned[r]];\n            spawned[r]++;\n            grid[r][0] = id;\n            posR[id] = r;\n            posC[id] = 0;\n        }\n    }\n\n    // Normal mode: reserve (i,1) for small buffers, avoid active gates (i,0).\n    // Panic mode: allow using any non-dispatch empty cell as storage.\n    bool isAllowedStorageCell(int r, int c) const {\n        if(c == 4) return false;\n        if(grid[r][c] != -1) return false;\n        if(craneAtCell(r,c)) return false;\n        if(!panic){\n            if(r > 0 && c == 1) return false;              // reserve buffer\n            if(c == 0 && spawned[r] < N) return false;     // active receiving gate\n        }\n        return true;\n    }\n\n    int countEmptyStorageCells() const {\n        int cnt=0;\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++){\n            if(isAllowedStorageCell(r,c)) cnt++;\n        }\n        return cnt;\n    }\n\n    pair<int,int> chooseStorageCellFor(int id, int fromR, int fromC) const {\n        int t = id / N;\n\n        // preferred spots (avoid buffer cells in normal mode)\n        vector<pair<int,int>> pref = {\n            {t,3},{t,2},{t,1},{t,0},{0,3},{0,2},{0,1},{0,0}\n        };\n        for(auto [r,c]: pref){\n            if(isAllowedStorageCell(r,c)) return {r,c};\n        }\n\n        int bestD = INT_MAX;\n        pair<int,int> best = {-1,-1};\n        for(int r=0;r<N;r++){\n            for(int c=0;c<N;c++){\n                if(!isAllowedStorageCell(r,c)) continue;\n                int d = abs(fromR-r) + abs(fromC-c);\n                if(r == t) d -= 1;\n                if(d < bestD){\n                    bestD = d;\n                    best = {r,c};\n                }\n            }\n        }\n        return best;\n    }\n\n    // Large crane movement restrictions in normal mode to avoid interfering with small cranes.\n    bool forbiddenForLarge(int r, int c, int tr, int tc) const {\n        if(panic) return false;\n        if(r > 0 && c == 0) return true; // avoid small crane lane\n        if(r > 0 && c == 1 && !(r==tr && c==tc)) return true; // pass-through buffer col forbidden\n        return false;\n    }\n\n    vector<char> bfsPathLarge(int sr, int sc, int tr, int tc) const {\n        if(sr==tr && sc==tc) return {};\n\n        // cannot go into cell occupied by another crane (unless that crane bombs this turn; handled outside BFS)\n        for(int k=1;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==tr && cranes[k].c==tc) return {};\n        }\n\n        array<array<int,N>,N> dist;\n        array<array<pair<int,int>,N>,N> prev;\n        array<array<char,N>,N> prevMove;\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            dist[i][j] = -1;\n            prev[i][j] = {-1,-1};\n            prevMove[i][j] = '?';\n        }\n\n        auto isBlocked = [&](int r, int c)->bool{\n            if(r<0||r>=N||c<0||c>=N) return true;\n            if(forbiddenForLarge(r,c,tr,tc)) return true;\n            for(int k=1;k<N;k++){\n                if(!cranes[k].alive) continue;\n                if(cranes[k].r==r && cranes[k].c==c) return true;\n            }\n            return false;\n        };\n\n        queue<pair<int,int>> q;\n        dist[sr][sc]=0;\n        q.push({sr,sc});\n\n        const int dr[4]={-1,1,0,0};\n        const int dc[4]={0,0,-1,1};\n        const char mv[4]={'U','D','L','R'};\n\n        while(!q.empty()){\n            auto [r,c]=q.front(); q.pop();\n            for(int k=0;k<4;k++){\n                int nr=r+dr[k], nc=c+dc[k];\n                if(isBlocked(nr,nc)) continue;\n                if(dist[nr][nc]!=-1) continue;\n                dist[nr][nc]=dist[r][c]+1;\n                prev[nr][nc]={r,c};\n                prevMove[nr][nc]=mv[k];\n                q.push({nr,nc});\n            }\n        }\n        if(dist[tr][tc]==-1) return {};\n\n        vector<char> path;\n        int r=tr,c=tc;\n        while(!(r==sr && c==sc)){\n            char m = prevMove[r][c];\n            path.push_back(m);\n            auto p=prev[r][c];\n            r=p.first; c=p.second;\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    int estimateCostLarge(int sr, int sc, int tr, int tc) const {\n        if(sr==tr && sc==tc) return 0;\n        auto p=bfsPathLarge(sr,sc,tr,tc);\n        if(p.empty()) return 1e9;\n        return (int)p.size();\n    }\n\n    // Small cranes i=1..4: simple gate->buffer shuttle in cols {0,1}.\n    // In panic mode: we will bomb them instead.\n    char decideSmallNormal(int i, int lockRow) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n        if(lockRow==i) return '.';\n\n        int r=cr.r,c=cr.c;\n        if(cr.holding){\n            if(c==0){\n                if(grid[i][1]==-1) return 'R';\n                return '.';\n            }else{ // c==1\n                if(grid[i][1]==-1) return 'Q';\n                return '.';\n            }\n        }else{\n            if(c==1) return 'L';\n            // c==0\n            if(grid[i][0]!=-1 && grid[i][1]==-1) return 'P';\n            return '.';\n        }\n    }\n\n    // In panic: drop if holding (Q if possible), otherwise bomb.\n    char decideSmallPanic(int i) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n        if(cr.holding){\n            // usually cell is empty right after P; Q should succeed if empty\n            if(grid[cr.r][cr.c]==-1) return 'Q';\n            return '.';\n        }else{\n            return 'B';\n        }\n    }\n\n    // Select a container on grid to dispatch (possibly out-of-order) with minimal score.\n    // Excludes cells inaccessible in normal mode.\n    int chooseBestDispatchCandidate(bool allowNonExpected) const {\n        const Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n\n        long long bestScore = (1LL<<60);\n        int bestId = -1;\n\n        for(int r=0;r<N;r++){\n            for(int c=0;c<4;c++){\n                int id = grid[r][c];\n                if(id==-1) continue;\n\n                if(!panic){\n                    if(r>0 && c==0) continue; // large avoids gates of small lanes\n                    if(r>0 && c==1){\n                        // can pick from buffer only if small is at (r,0) and not holding (and we will lock)\n                        const Crane &s = cranes[r];\n                        if(!(s.alive && s.r==r && s.c==0 && !s.holding)) continue;\n                    }\n                } else {\n                    // in panic, still cannot pick from under another crane\n                    if(craneAtCell(r,c) && !(cranes[0].r==r && cranes[0].c==c)) continue;\n                }\n\n                int t = id / N;\n                int idx = id % N;\n\n                int exp = expectedId(t);\n                bool isExpected = (exp == id);\n                if(!allowNonExpected && !isExpected) continue;\n\n                int inv = invCostIfDispatch(id);\n\n                int c1 = estimateCostLarge(lr,lc,r,c);\n                int c2 = estimateCostLarge(r,c,t,4);\n                if(c1>=1e9 || c2>=1e9) continue;\n\n                // score: prioritize 0 inversion, then travel\n                long long score = 100000LL*inv + 10LL*(c1 + c2) + (isExpected?0:50);\n                if(score < bestScore){\n                    bestScore = score;\n                    bestId = id;\n                }\n            }\n        }\n        return bestId;\n    }\n\n    void buildLargePlan(){\n        plan0.clear();\n        Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n\n        // If holding, prefer to dispatch it (always progress), otherwise store.\n        if(L.holding){\n            int id = L.held;\n            int t = id / N;\n            // Try dispatch directly\n            auto p2 = bfsPathLarge(lr,lc,t,4);\n            if(lr==t && lc==4) p2.clear();\n            if(!p2.empty() || (lr==t && lc==4)){\n                for(char m: p2) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            // else store somewhere\n            auto st = chooseStorageCellFor(id, lr, lc);\n            if(st.first!=-1){\n                auto p1 = bfsPathLarge(lr,lc,st.first,st.second);\n                for(char m: p1) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            plan0.push_back('.');\n            return;\n        }\n\n        // 1) Dispatch an expected container if possible\n        int idExp = chooseBestDispatchCandidate(false);\n        if(idExp!=-1){\n            int pr=posR[idExp], pc=posC[idExp];\n            int t = idExp / N;\n            auto p1 = bfsPathLarge(lr,lc,pr,pc);\n            if(!(lr==pr && lc==pc) && p1.empty()){ plan0.push_back('.'); return; }\n            auto p2 = bfsPathLarge(pr,pc,t,4);\n            if(!(pr==t && pc==4) && p2.empty()){ plan0.push_back('.'); return; }\n            for(char m: p1) plan0.push_back(m);\n            plan0.push_back('P');\n            for(char m: p2) plan0.push_back(m);\n            plan0.push_back('Q');\n            return;\n        }\n\n        // 2) If storage is tight, dispatch some container (out-of-order) to free space\n        int emptyStorage = countEmptyStorageCells();\n        if(emptyStorage <= STORAGE_TIGHT){\n            int idAny = chooseBestDispatchCandidate(true);\n            if(idAny!=-1){\n                int pr=posR[idAny], pc=posC[idAny];\n                int t = idAny / N;\n                auto p1 = bfsPathLarge(lr,lc,pr,pc);\n                if(!(lr==pr && lc==pc) && p1.empty()){ plan0.push_back('.'); return; }\n                auto p2 = bfsPathLarge(pr,pc,t,4);\n                if(!(pr==t && pc==4) && p2.empty()){ plan0.push_back('.'); return; }\n                for(char m: p1) plan0.push_back(m);\n                plan0.push_back('P');\n                for(char m: p2) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n        }\n\n        // 3) Otherwise, move one buffer/gate container into storage to keep intake flowing\n        auto tryPickStore = [&](int pr,int pc)->bool{\n            int id = grid[pr][pc];\n            if(id==-1) return false;\n            if(!panic){\n                if(pr>0 && pc==1){\n                    const Crane &s = cranes[pr];\n                    if(!(s.alive && s.r==pr && s.c==0 && !s.holding)) return false;\n                }\n                if(pr>0 && pc==0) return false;\n            }\n\n            auto st = chooseStorageCellFor(id, pr, pc);\n            if(st.first==-1) return false;\n\n            auto p1 = bfsPathLarge(lr,lc,pr,pc);\n            if(!(lr==pr && lc==pc) && p1.empty()) return false;\n            auto p2 = bfsPathLarge(pr,pc,st.first,st.second);\n            if(!(pr==st.first && pc==st.second) && p2.empty()) return false;\n\n            for(char m: p1) plan0.push_back(m);\n            plan0.push_back('P');\n            for(char m: p2) plan0.push_back(m);\n            plan0.push_back('Q');\n            return true;\n        };\n\n        // pick from a full buffer first (rows 1..4)\n        int bestRow=-1, bestD=1e9;\n        for(int i=1;i<N;i++){\n            if(grid[i][1]==-1) continue;\n            const Crane &s = cranes[i];\n            if(!panic && !(s.alive && s.r==i && s.c==0 && !s.holding)) continue;\n            int d = estimateCostLarge(lr,lc,i,1);\n            if(d < bestD){\n                bestD = d;\n                bestRow = i;\n            }\n        }\n        if(bestRow!=-1 && tryPickStore(bestRow,1)) return;\n\n        // clear row0 gate if occupied (row0 has no small crane)\n        if(grid[0][0]!=-1 && tryPickStore(0,0)) return;\n\n        // else idle\n        plan0.push_back('.');\n    }\n\n    struct MoveInfo { int sr,sc, dr,dc; };\n\n    bool validateActions(const array<char,N>& act) const {\n        array<MoveInfo,N> mv;\n        array<bool,N> willBomb{};\n        for(int k=0;k<N;k++){\n            const Crane &cr = cranes[k];\n            willBomb[k] = false;\n\n            if(!cr.alive){\n                if(act[k] != '.') return false;\n                mv[k] = {cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n\n            char a = act[k];\n            if(a=='B'){\n                if(cr.holding) return false;\n                willBomb[k] = true;\n                mv[k] = {cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n\n            int r=cr.r,c=cr.c;\n            int nr=r,nc=c;\n            if(a=='U') nr--;\n            else if(a=='D') nr++;\n            else if(a=='L') nc--;\n            else if(a=='R') nc++;\n            else if(a=='P'||a=='Q'||a=='.') { /* stay */ }\n            else return false;\n\n            if(nr<0||nr>=N||nc<0||nc>=N) return false;\n\n            if((a=='U'||a=='D'||a=='L'||a=='R') && !cr.large && cr.holding){\n                if(grid[nr][nc]!=-1) return false;\n            }\n\n            if(a=='P'){\n                if(cr.holding) return false;\n                if(grid[r][c]==-1) return false;\n            }\n            if(a=='Q'){\n                if(!cr.holding) return false;\n                if(grid[r][c]!=-1) return false;\n            }\n\n            mv[k] = {r,c,nr,nc};\n        }\n\n        // destination overlap among non-bombed alive cranes\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                if(mv[i].dr==mv[j].dr && mv[i].dc==mv[j].dc) return false;\n            }\n        }\n\n        // swap (passing) among non-bombed\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                bool swap = (mv[i].dr==mv[j].sr && mv[i].dc==mv[j].sc &&\n                             mv[j].dr==mv[i].sr && mv[j].dc==mv[i].sc &&\n                             !(mv[i].sr==mv[j].sr && mv[i].sc==mv[j].sc));\n                if(swap) return false;\n            }\n        }\n        return true;\n    }\n\n    void applyActions(const array<char,N>& act){\n        // compute willBomb and move destinations\n        array<bool,N> willBomb{};\n        array<int,N> nr, nc;\n        for(int k=0;k<N;k++){\n            nr[k]=cranes[k].r;\n            nc[k]=cranes[k].c;\n            willBomb[k] = false;\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            if(a=='B'){\n                willBomb[k]=true;\n                continue;\n            }\n            if(a=='U') nr[k]--;\n            else if(a=='D') nr[k]++;\n            else if(a=='L') nc[k]--;\n            else if(a=='R') nc[k]++;\n        }\n\n        // apply bombs (removal) - removal happens effectively during the action step,\n        // and other cranes may move into that cell same turn; our validator already allowed it.\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(willBomb[k]){\n                cranes[k].alive = false;\n            }\n        }\n\n        // apply moves for remaining alive\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            if(a=='B') continue;\n            cranes[k].r = nr[k];\n            cranes[k].c = nc[k];\n        }\n\n        // apply P/Q\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            int r=cranes[k].r, c=cranes[k].c;\n            if(a=='P'){\n                int id = grid[r][c];\n                grid[r][c] = -1;\n                posR[id] = posC[id] = -1;\n                cranes[k].holding = true;\n                cranes[k].held = id;\n            } else if(a=='Q'){\n                int id = cranes[k].held;\n                grid[r][c] = id;\n                posR[id] = r;\n                posC[id] = c;\n                cranes[k].holding = false;\n                cranes[k].held = -1;\n            }\n        }\n\n        // dispatch\n        for(int r=0;r<N;r++){\n            int id = grid[r][4];\n            if(id==-1) continue;\n            grid[r][4] = -1;\n            posR[id] = posC[id] = -1;\n\n            int t = id / N;\n            int idx = id % N;\n            if(((dispMask[t] >> idx) & 1) == 0){\n                dispMask[t] |= (1<<idx);\n                dispatchedCount++;\n            }\n        }\n    }\n\n    void run(){\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            // Step1 spawn\n            spawnPhase();\n\n            // update progress counters\n            if(dispatchedCount != lastDispatchedCount){\n                lastDispatchedCount = dispatchedCount;\n                noProgressTurns = 0;\n            } else {\n                noProgressTurns++;\n            }\n            if(!panic && noProgressTurns >= STUCK_LIMIT){\n                panic = true;\n                plan0.clear();\n            }\n\n            // decide actions\n            array<char,N> act;\n            act.fill('.');\n\n            // decide large\n            if(plan0.empty()) buildLargePlan();\n            act[0] = plan0.empty()?'.':plan0.front();\n\n            // compute which row to lock (to avoid collisions on buffer cell (i,1))\n            int lockRow = -1;\n            auto &L = cranes[0];\n            if(L.alive){\n                int lr=L.r, lc=L.c;\n                int dr=lr, dc=lc;\n                if(act[0]=='U') dr--;\n                else if(act[0]=='D') dr++;\n                else if(act[0]=='L') dc--;\n                else if(act[0]=='R') dc++;\n                // if large will be at (row>0, col==1) after move OR currently there doing P/Q, lock that row\n                if(dr>0 && dc==1) lockRow = dr;\n                if(lr>0 && lc==1 && (act[0]=='P' || act[0]=='Q' || act[0]=='.')) lockRow = lr;\n            }\n\n            // decide smalls\n            for(int i=1;i<N;i++){\n                act[i] = panic ? decideSmallPanic(i) : decideSmallNormal(i, lockRow);\n            }\n\n            // validate; conservative fallback\n            if(!validateActions(act)){\n                // first freeze smalls\n                array<char,N> act2 = act;\n                for(int i=1;i<N;i++) if(!panic) act2[i]='.';\n                if(validateActions(act2)){\n                    act = act2;\n                } else {\n                    // freeze all\n                    array<char,N> act3;\n                    act3.fill('.');\n                    if(validateActions(act3)) act = act3;\n                    else {\n                        // should never happen; but keep safe output\n                        act = act3;\n                    }\n                }\n            }\n\n            // consume plan step if used\n            if(!plan0.empty() && act[0]==plan0.front()){\n                plan0.pop_front();\n            } else if(!plan0.empty() && act[0]!='.'){\n                plan0.clear();\n            }\n\n            // output\n            for(int i=0;i<N;i++) out[i].push_back(act[i]);\n\n            // Step2+3\n            applyActions(act);\n\n            turn++;\n        }\n\n        // ensure length >= 1\n        if(turn==0){\n            for(int i=0;i<N;i++) out[i].push_back('.');\n        }\n    }\n\n    void print() const {\n        for(int i=0;i<N;i++) cout << out[i] << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<vector<int>> Ain(n, vector<int>(n));\n    for(int i=0;i<n;i++){\n        for(int j=0;j<n;j++) cin >> Ain[i][j];\n    }\n\n    Solver solver(Ain);\n    solver.run();\n    solver.print();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF = (1LL<<62);\n\nstatic inline int id(int r, int c, int N){ return r*N + c; }\nstatic inline int r_of(int v, int N){ return v / N; }\nstatic inline int c_of(int v, int N){ return v % N; }\n\nstatic inline char move_dir(int from, int to, int N){\n    int fr = r_of(from, N), fc = c_of(from, N);\n    int tr = r_of(to, N), tc = c_of(to, N);\n    if (tr == fr-1 && tc == fc) return 'U';\n    if (tr == fr+1 && tc == fc) return 'D';\n    if (tr == fr && tc == fc-1) return 'L';\n    if (tr == fr && tc == fc+1) return 'R';\n    return '?';\n}\n\nstruct Emitter {\n    vector<string> ops;\n    void emit_move(char c) { ops.emplace_back(1, c); }\n    void emit_amount(char sign, long long d) {\n        while (d > 0) {\n            long long x = min(d, 1000000LL);\n            ops.push_back(string(1, sign) + to_string(x));\n            d -= x;\n        }\n    }\n};\n\nstatic inline bool would_create_cycle(const vector<int>& parent, int u, int newp){\n    int x = newp;\n    while(x != -1){\n        if(x == u) return true;\n        x = parent[x];\n    }\n    return false;\n}\n\n// Precomputed permutations of indices 0..k-1 for k<=4\nstatic vector<array<int,4>> perms[5];\n\nstatic void init_perms(){\n    for(int k=0;k<=4;k++){\n        array<int,4> a{};\n        for(int i=0;i<4;i++) a[i]=i;\n        vector<int> v(k);\n        iota(v.begin(), v.end(), 0);\n        do{\n            array<int,4> p{};\n            for(int i=0;i<k;i++) p[i]=v[i];\n            perms[k].push_back(p);\n        }while(next_permutation(v.begin(), v.end()));\n    }\n}\n\nstruct EvalResult {\n    long long cost;\n};\n\n// Evaluate cost for a given rooted spanning tree (root=0) under:\n// - postorder fixing\n// - entering child c with load need[c]=max(0,-subsum[c]) by adjusting at parent (may borrow/dump at parent)\n// Child ordering is optimized exactly per node (degree<=4).\nstatic long long eval_cost_tree_optorder(\n    const vector<int>& parent,\n    const vector<int>& h,\n    int N\n){\n    int V = N*N;\n\n    // children in fixed arrays\n    vector<array<int,4>> child(V);\n    vector<uint8_t> deg(V, 0);\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        if(p < 0) return INF;\n        if(deg[p] >= 4) return INF;\n        child[p][deg[p]++] = v;\n    }\n\n    // postorder\n    vector<uint8_t> it(V, 0);\n    vector<int> st;\n    st.reserve(V);\n    st.push_back(0);\n    vector<int> post;\n    post.reserve(V);\n\n    while(!st.empty()){\n        int v = st.back();\n        if(it[v] < deg[v]){\n            int c = child[v][it[v]++];\n            st.push_back(c);\n        }else{\n            post.push_back(v);\n            st.pop_back();\n        }\n    }\n    if((int)post.size() != V) return INF;\n\n    vector<long long> subsum(V, 0), need(V, 0), out(V, 0);\n    for(int v: post){\n        long long s = h[v];\n        for(int i=0;i<deg[v];i++){\n            int c = child[v][i];\n            s += subsum[c];\n        }\n        subsum[v] = s;\n    }\n    if(subsum[0] != 0) return INF; // should always hold\n\n    for(int v=0; v<V; v++){\n        need[v] = max(0LL, -subsum[v]);\n        out[v]  = max(0LL,  subsum[v]);\n    }\n\n    vector<long long> dp(V, INF);\n\n    for(int v: post){\n        int k = deg[v];\n\n        long long base = 0;\n        for(int i=0;i<k;i++){\n            int c = child[v][i];\n            if(dp[c] >= INF/2) { base = INF; break; }\n            base += dp[c];\n            // edge pair move costs: down(100+need[c]) + up(100+out[c])\n            base += 200 + need[c] + out[c];\n        }\n        if(base >= INF/2) { dp[v] = INF; continue; }\n\n        long long best = INF;\n\n        for(const auto &pidx : perms[k]){\n            long long curH = h[v];\n            long long load = need[v];\n            long long cost = base;\n\n            for(int j=0;j<k;j++){\n                int c = child[v][pidx[j]];\n                long long target = need[c];\n                if(load < target){\n                    long long d = target - load;\n                    cost += d;\n                    curH -= d;\n                    load = target;\n                }else if(load > target){\n                    long long d = load - target;\n                    cost += d;\n                    curH += d;\n                    load = target;\n                }\n                // after returning from child subtree, load is exactly out[c]\n                load = out[c];\n            }\n\n            // fix v to 0\n            if(curH > 0){\n                cost += curH;\n                load += curH;\n            }else if(curH < 0){\n                long long x = -curH;\n                cost += x;\n                load -= x;\n                if(load < 0) { cost = INF; }\n            }\n            if(cost < INF && load != out[v]) cost = INF;\n\n            best = min(best, cost);\n        }\n\n        dp[v] = best;\n    }\n\n    return dp[0];\n}\n\nstruct Plan {\n    long long cost = INF;\n    vector<long long> need, out, subsum;\n    vector<array<int,4>> order; // ordered children\n    vector<uint8_t> deg;\n    vector<int> parent;\n};\n\nstatic Plan build_plan_tree_optorder(const vector<int>& parent, const vector<int>& h, int N){\n    int V = N*N;\n    Plan plan;\n    plan.parent = parent;\n    plan.need.assign(V, 0);\n    plan.out.assign(V, 0);\n    plan.subsum.assign(V, 0);\n    plan.order.assign(V, array<int,4>{});\n    plan.deg.assign(V, 0);\n\n    vector<array<int,4>> child(V);\n    vector<uint8_t> deg(V, 0);\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        deg[p]++;\n        child[p][deg[p]-1] = v;\n    }\n\n    vector<uint8_t> it(V, 0);\n    vector<int> st;\n    st.reserve(V);\n    st.push_back(0);\n    vector<int> post;\n    post.reserve(V);\n    while(!st.empty()){\n        int v = st.back();\n        if(it[v] < deg[v]){\n            int c = child[v][it[v]++];\n            st.push_back(c);\n        }else{\n            post.push_back(v);\n            st.pop_back();\n        }\n    }\n\n    for(int v: post){\n        long long s = h[v];\n        for(int i=0;i<deg[v];i++) s += plan.subsum[child[v][i]];\n        plan.subsum[v] = s;\n    }\n    for(int v=0; v<V; v++){\n        plan.need[v] = max(0LL, -plan.subsum[v]);\n        plan.out[v]  = max(0LL,  plan.subsum[v]);\n    }\n\n    vector<long long> dp(V, INF);\n\n    for(int v: post){\n        int k = deg[v];\n        long long base = 0;\n        for(int i=0;i<k;i++){\n            int c = child[v][i];\n            base += dp[c];\n            base += 200 + plan.need[c] + plan.out[c];\n        }\n\n        long long best = INF;\n        array<int,4> bestOrd{};\n\n        for(const auto &pidx: perms[k]){\n            long long curH = h[v];\n            long long load = plan.need[v];\n            long long cost = base;\n\n            for(int j=0;j<k;j++){\n                int c = child[v][pidx[j]];\n                long long target = plan.need[c];\n                if(load < target){\n                    long long d = target - load;\n                    cost += d;\n                    curH -= d;\n                    load = target;\n                }else if(load > target){\n                    long long d = load - target;\n                    cost += d;\n                    curH += d;\n                    load = target;\n                }\n                load = plan.out[c];\n            }\n\n            if(curH > 0){\n                cost += curH;\n                load += curH;\n            }else if(curH < 0){\n                long long x = -curH;\n                cost += x;\n                load -= x;\n                if(load < 0) cost = INF;\n            }\n            if(cost < INF && load != plan.out[v]) cost = INF;\n\n            if(cost < best){\n                best = cost;\n                for(int j=0;j<k;j++) bestOrd[j] = child[v][pidx[j]];\n            }\n        }\n\n        dp[v] = best;\n        plan.deg[v] = deg[v];\n        plan.order[v] = bestOrd;\n    }\n\n    plan.cost = dp[0];\n    return plan;\n}\n\n// Spanning tree generators\nstatic vector<int> bfs_tree(int N, const array<int,4>& ord){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        int r=r_of(v,N), c=c_of(v,N);\n        for(int t: ord){\n            int nr=r, nc=c;\n            if(t==0) nr--;\n            if(t==1) nr++;\n            if(t==2) nc--;\n            if(t==3) nc++;\n            if(nr<0||nr>=N||nc<0||nc>=N) continue;\n            int u=id(nr,nc,N);\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstatic vector<int> random_dfs_tree(int N, const vector<array<int,4>>& adj, const vector<uint8_t>& adeg, mt19937_64& rng){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    vector<int> st;\n    st.reserve(V);\n    st.push_back(0);\n    vis[0]=1;\n\n    while(!st.empty()){\n        int v = st.back();\n        int k = adeg[v];\n        int cand[4]; int cc=0;\n        for(int i=0;i<k;i++){\n            int u = adj[v][i];\n            if(!vis[u]) cand[cc++] = u;\n        }\n        if(cc==0){\n            st.pop_back();\n        }else{\n            int u = cand[uniform_int_distribution<int>(0, cc-1)(rng)];\n            vis[u]=1;\n            parent[u]=v;\n            st.push_back(u);\n        }\n    }\n    return parent;\n}\n\nstruct DSU{\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(),p.end(),0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstatic vector<int> random_kruskal_tree(int N, const vector<pair<int,int>>& edges, mt19937_64& rng){\n    int V = N*N;\n    vector<pair<int,int>> e = edges;\n    shuffle(e.begin(), e.end(), rng);\n\n    DSU dsu(V);\n    vector<vector<int>> g(V);\n    g.assign(V, {});\n    int used = 0;\n    for(auto [a,b]: e){\n        if(dsu.unite(a,b)){\n            g[a].push_back(b);\n            g[b].push_back(a);\n            used++;\n            if(used == V-1) break;\n        }\n    }\n\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        for(int u: g[v]){\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstatic void build_ops_from_plan(const Plan& plan, const vector<int>& h, int N, vector<string>& out_ops){\n    int V = N*N;\n    vector<long long> curH(V);\n    for(int i=0;i<V;i++) curH[i] = h[i];\n\n    Emitter em;\n    long long load = 0;\n\n    struct Frame{ int v; int idx; };\n    vector<Frame> st;\n    st.reserve(V);\n    st.push_back({0,0});\n\n    while(!st.empty()){\n        int v = st.back().v;\n        int &idx = st.back().idx;\n        int k = plan.deg[v];\n\n        if(idx < k){\n            int c = plan.order[v][idx++];\n            long long target = plan.need[c];\n\n            if(load < target){\n                long long d = target - load;\n                em.emit_amount('+', d);\n                curH[v] -= d; // borrow/load from v (can go negative)\n                load = target;\n            }else if(load > target){\n                long long d = load - target;\n                em.emit_amount('-', d);\n                curH[v] += d; // dump to v\n                load = target;\n            }\n\n            em.emit_move(move_dir(v, c, N));\n            st.push_back({c,0});\n        }else{\n            // fix v to 0\n            if(curH[v] > 0){\n                long long x = curH[v];\n                em.emit_amount('+', x);\n                load += x;\n                curH[v] = 0;\n            }else if(curH[v] < 0){\n                long long x = -curH[v];\n                em.emit_amount('-', x);\n                load -= x;\n                curH[v] = 0;\n            }\n\n            st.pop_back();\n            if(st.empty()) break;\n            int p = st.back().v;\n            em.emit_move(move_dir(v, p, N));\n        }\n    }\n\n    out_ops = std::move(em.ops);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_perms();\n\n    int N;\n    cin >> N;\n    int V = N*N;\n    vector<int> h(V);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin >> h[id(i,j,N)];\n        }\n    }\n\n    // adjacency as fixed arrays\n    vector<array<int,4>> adj(V);\n    vector<uint8_t> adeg(V, 0);\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v = id(r,c,N);\n            uint8_t k = 0;\n            if(r>0) adj[v][k++] = id(r-1,c,N);\n            if(r+1<N) adj[v][k++] = id(r+1,c,N);\n            if(c>0) adj[v][k++] = id(r,c-1,N);\n            if(c+1<N) adj[v][k++] = id(r,c+1,N);\n            adeg[v] = k;\n        }\n    }\n\n    vector<pair<int,int>> edges;\n    edges.reserve(2*N*(N-1));\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v=id(r,c,N);\n            if(r+1<N) edges.push_back({v, id(r+1,c,N)});\n            if(c+1<N) edges.push_back({v, id(r,c+1,N)});\n        }\n    }\n\n    mt19937_64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    vector<int> best_parent;\n    long long best_cost = INF;\n\n    auto consider = [&](const vector<int>& parent){\n        long long c = eval_cost_tree_optorder(parent, h, N);\n        if(c < best_cost){\n            best_cost = c;\n            best_parent = parent;\n        }\n    };\n\n    // initial candidates\n    {\n        array<array<int,4>,4> orders = {{\n            {3,1,2,0}, // R,D,L,U\n            {1,3,2,0}, // D,R,L,U\n            {3,2,1,0}, // R,L,D,U\n            {1,2,3,0}  // D,L,R,U\n        }};\n        for(auto ord: orders) consider(bfs_tree(N, ord));\n    }\n    for(int i=0;i<20;i++) consider(random_kruskal_tree(N, edges, rng));\n    for(int i=0;i<30;i++) consider(random_dfs_tree(N, adj, adeg, rng));\n\n    if(best_parent.empty()){\n        best_parent = bfs_tree(N, {3,1,2,0});\n        best_cost = eval_cost_tree_optorder(best_parent, h, N);\n    }\n\n    // SA on parent edges\n    vector<int> cur_parent = best_parent;\n    long long cur_cost = best_cost;\n\n    const double TL = 1.90;\n    long long iters = 0;\n\n    while(elapsed() < TL){\n        iters++;\n        double t = elapsed() / TL;\n        double T0 = 2500.0, T1 = 30.0;\n        double temp = T0 * (1.0 - t) + T1 * t;\n\n        int u = uniform_int_distribution<int>(1, V-1)(rng);\n        int k = adeg[u];\n        int newp = adj[u][uniform_int_distribution<int>(0, k-1)(rng)];\n        if(newp == cur_parent[u]) continue;\n        if(would_create_cycle(cur_parent, u, newp)) continue;\n\n        int oldp = cur_parent[u];\n        cur_parent[u] = newp;\n\n        long long nxt_cost = eval_cost_tree_optorder(cur_parent, h, N);\n        if(nxt_cost >= INF/2){\n            cur_parent[u] = oldp;\n            continue;\n        }\n\n        bool accept = false;\n        if(nxt_cost <= cur_cost) accept = true;\n        else{\n            double diff = (double)(cur_cost - nxt_cost); // negative\n            double prob = exp(diff / temp);\n            double r = uniform_real_distribution<double>(0.0, 1.0)(rng);\n            if(r < prob) accept = true;\n        }\n\n        if(accept){\n            cur_cost = nxt_cost;\n            if(cur_cost < best_cost){\n                best_cost = cur_cost;\n                best_parent = cur_parent;\n            }\n        }else{\n            cur_parent[u] = oldp;\n        }\n    }\n\n    // Build final plan and output operations\n    Plan plan = build_plan_tree_optorder(best_parent, h, N);\n\n    vector<string> ops;\n    build_ops_from_plan(plan, h, N, ops);\n\n    if((int)ops.size() > 100000){\n        ops.clear(); // extremely unlikely\n    }\n\n    for(auto &s: ops) cout << s << \"\\n\";\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ull;\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n};\n\nstatic constexpr int MMAX = 15;\n\nstruct Seed {\n    array<uint8_t, MMAX> x{};\n    int V = 0;\n    int peak = 0;\n};\n\nstatic inline int diffCount(const Seed& a, const Seed& b, int M) {\n    int d = 0;\n    for (int i = 0; i < M; i++) d += (a.x[i] != b.x[i]);\n    return d;\n}\nstatic inline int sumAbsDiff(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += abs((int)a.x[i] - (int)b.x[i]);\n    return s;\n}\nstatic inline int potentialSumMax(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += max<int>(a.x[i], b.x[i]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    using Clock = chrono::steady_clock;\n    using TimePoint = Clock::time_point;\n\n    int N, M, T;\n    cin >> N >> M >> T;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60\n    const int P = N * N;                    // 36\n\n    vector<Seed> seeds(SEED_COUNT);\n\n    auto readSeeds = [&]() {\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int sum = 0, pk = 0;\n            for (int l = 0; l < M; l++) {\n                int v;\n                cin >> v;\n                seeds[k].x[l] = (uint8_t)v;\n                sum += v;\n                pk = max(pk, v);\n            }\n            seeds[k].V = sum;\n            seeds[k].peak = pk;\n        }\n    };\n\n    readSeeds();\n\n    // Grid neighbors and edges\n    vector<vector<int>> neigh(P);\n    vector<pair<int,int>> edges;\n    vector<int> degree(P, 0);\n\n    auto id = [&](int i, int j) { return i * N + j; };\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int v = id(i, j);\n            if (i > 0) neigh[v].push_back(id(i - 1, j));\n            if (i + 1 < N) neigh[v].push_back(id(i + 1, j));\n            if (j > 0) neigh[v].push_back(id(i, j - 1));\n            if (j + 1 < N) neigh[v].push_back(id(i, j + 1));\n            degree[v] = (int)neigh[v].size();\n        }\n    }\n    for (int i = 0; i < N; i++)\n        for (int j = 0; j + 1 < N; j++)\n            edges.push_back({id(i, j), id(i, j + 1)});\n    for (int i = 0; i + 1 < N; i++)\n        for (int j = 0; j < N; j++)\n            edges.push_back({id(i, j), id(i + 1, j)});\n\n    vector<int> posOrder(P);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n        if (degree[a] != degree[b]) return degree[a] > degree[b];\n        return a < b;\n    });\n\n    vector<int> centers;\n    for (int p = 0; p < P; p++) if (degree[p] == 4) centers.push_back(p);\n\n    RNG rng;\n    TimePoint globalStart = Clock::now();\n    const double TIME_LIMIT = 1.90;\n\n    auto evalObjective = [&](const vector<int>& perm, const vector<vector<double>>& w) -> double {\n        double s = 0.0;\n        for (auto [u, v] : edges) s += w[perm[u]][perm[v]];\n        return s;\n    };\n\n    auto runSA = [&](vector<int> perm,\n                     const vector<vector<double>>& w,\n                     TimePoint endTime) -> pair<double, vector<int>> {\n        double cur = evalObjective(perm, w);\n        double best = cur;\n        vector<int> bestPerm = perm;\n\n        const double tempStart = 500.0;\n        const double tempEnd = 10.0;\n\n        TimePoint t0 = Clock::now();\n        double total = chrono::duration<double>(endTime - t0).count();\n        if (total <= 1e-9) return {cur, perm};\n\n        while (Clock::now() < endTime) {\n            int a = rng.nextInt(P);\n            int b = rng.nextInt(P);\n            if (a == b) continue;\n\n            int la = perm[a];\n            int lb = perm[b];\n            double delta = 0.0;\n\n            for (int na : neigh[a]) {\n                if (na == b) continue;\n                int lx = perm[na];\n                delta += w[lb][lx] - w[la][lx];\n            }\n            for (int nb : neigh[b]) {\n                if (nb == a) continue;\n                int lx = perm[nb];\n                delta += w[la][lx] - w[lb][lx];\n            }\n\n            double prog = chrono::duration<double>(Clock::now() - t0).count() / total;\n            prog = min(1.0, max(0.0, prog));\n            double temp = tempStart * pow(tempEnd / tempStart, prog);\n\n            bool accept = (delta >= 0.0) || (rng.nextDouble() < exp(delta / temp));\n            if (accept) {\n                swap(perm[a], perm[b]);\n                cur += delta;\n                if (cur > best) {\n                    best = cur;\n                    bestPerm = perm;\n                }\n            }\n        }\n        return {best, bestPerm};\n    };\n\n    for (int t = 0; t < T; t++) {\n        // per-turn time budget\n        double elapsed = chrono::duration<double>(Clock::now() - globalStart).count();\n        double remaining = max(0.0, TIME_LIMIT - elapsed);\n        double perTurn = remaining / max(1, (T - t));\n\n        TimePoint turnStart = Clock::now();\n        TimePoint turnEnd = turnStart + chrono::duration_cast<Clock::duration>(chrono::duration<double>(perTurn * 0.97));\n\n        // ---- 1) Selection 60 -> 36 (mostly like the better baseline) ----\n        vector<int> idx(SEED_COUNT);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (seeds[a].V != seeds[b].V) return seeds[a].V > seeds[b].V;\n            return a < b;\n        });\n\n        vector<int> selected;\n        selected.reserve(P);\n        vector<char> used(SEED_COUNT, 0);\n        vector<char> prot(SEED_COUNT, 0);\n\n        auto addSeed = [&](int k, bool protect) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n            if (protect) prot[k] = 1;\n        };\n\n        int eliteCount = 10;\n        int partnerFor = 8;\n\n        for (int i = 0; i < eliteCount; i++) addSeed(idx[i], true);\n\n        // similar partner for top elites (preservation)\n        for (int i = 0; i < partnerFor; i++) {\n            int e = idx[i];\n            int best = -1;\n            int bestScore = INT_MAX;\n            for (int j = 0; j < SEED_COUNT; j++) {\n                if (j == e || used[j]) continue;\n                int d = diffCount(seeds[e], seeds[j], M);\n                int vd = abs(seeds[e].V - seeds[j].V);\n                int score = d * 120 + vd; // prioritize similarity\n                if (score < bestScore) {\n                    bestScore = score;\n                    best = j;\n                } else if (score == bestScore && seeds[j].V > (best == -1 ? -1 : seeds[best].V)) {\n                    best = j;\n                }\n            }\n            if (best != -1) addSeed(best, true);\n        }\n\n        // per-dimension best keepers\n        const int perDimTake = 1;\n        for (int l = 0; l < M; l++) {\n            int best = -1;\n            for (int k = 0; k < SEED_COUNT; k++) {\n                if (used[k]) continue;\n                if (best == -1 ||\n                    seeds[k].x[l] > seeds[best].x[l] ||\n                    (seeds[k].x[l] == seeds[best].x[l] && seeds[k].V > seeds[best].V)) {\n                    best = k;\n                }\n            }\n            if (best != -1) addSeed(best, false);\n        }\n\n        // fill remaining with high mixed score\n        auto mixedScore = [&](int k) -> int {\n            return seeds[k].V * 10 + seeds[k].peak * 6;\n        };\n\n        vector<int> rest;\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        sort(rest.begin(), rest.end(), [&](int a, int b) {\n            int sa = mixedScore(a), sb = mixedScore(b);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n        for (int k : rest) {\n            if ((int)selected.size() >= P) break;\n            addSeed(k, false);\n        }\n\n        // prune if over\n        if ((int)selected.size() > P) {\n            auto importance = [&](int k) -> int {\n                return seeds[k].V * 10 + seeds[k].peak * 3;\n            };\n            vector<int> removable;\n            for (int k : selected) if (!prot[k]) removable.push_back(k);\n            sort(removable.begin(), removable.end(), [&](int a, int b) {\n                int ia = importance(a), ib = importance(b);\n                if (ia != ib) return ia < ib;\n                return a > b;\n            });\n            int ptr = 0;\n            while ((int)selected.size() > P && ptr < (int)removable.size()) {\n                int rm = removable[ptr++];\n                auto it = find(selected.begin(), selected.end(), rm);\n                if (it != selected.end()) selected.erase(it);\n            }\n            while ((int)selected.size() > P) selected.pop_back();\n        }\n\n        // local mapping\n        vector<int> globOfLocal(P);\n        for (int i = 0; i < P; i++) globOfLocal[i] = selected[i];\n\n        // ---- 2) Pair weights (keep strong \"potential\" model, add small magnitude penalty) ----\n        double phase = (T == 1) ? 1.0 : (double)t / (double)(T - 1);\n\n        double lambdaDiff = 1.7 + 2.3 * phase;      // diffCount penalty\n        double rhoMinV    = 0.06 + 0.40 * phase;    // robustness increases late\n        double muAbs      = 0.001 + 0.004 * phase;  // small magnitude-aware penalty\n\n        vector<vector<double>> w(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                const Seed& A = seeds[globOfLocal[i]];\n                const Seed& B = seeds[globOfLocal[j]];\n                int pot = potentialSumMax(A, B, M);\n                int d = diffCount(A, B, M);\n                int sad = sumAbsDiff(A, B, M);\n                int mn = min(A.V, B.V);\n                double score = (double)pot + rhoMinV * (double)mn - lambdaDiff * (double)d - muAbs * (double)sad;\n                w[i][j] = w[j][i] = score;\n            }\n        }\n\n        // ---- 3) Initial layouts (multi-start) ----\n        auto localImportance = [&](int li) -> int {\n            int g = globOfLocal[li];\n            return seeds[g].V * 10 + seeds[g].peak * 3;\n        };\n\n        vector<int> localSorted(P);\n        iota(localSorted.begin(), localSorted.end(), 0);\n        sort(localSorted.begin(), localSorted.end(), [&](int a, int b) {\n            int ia = localImportance(a), ib = localImportance(b);\n            if (ia != ib) return ia > ib;\n            return a < b;\n        });\n\n        // init0: importance -> high degree\n        vector<int> init0(P);\n        for (int k = 0; k < P; k++) init0[posOrder[k]] = localSorted[k];\n\n        // init1: random permutation\n        vector<int> init1 = init0;\n        for (int i = P - 1; i > 0; i--) swap(init1[i], init1[rng.nextInt(i + 1)]);\n\n        // init2: greedy incremental\n        vector<int> init2(P, -1);\n        vector<char> usedLocal(P, 0);\n        for (int idxPos = 0; idxPos < P; idxPos++) {\n            int pos = posOrder[idxPos];\n            int bestL = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!usedLocal[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init2[nb] != -1) gain += w[li][init2[nb]];\n                gain += 0.002 * localImportance(li);\n                if (gain > bestGain) { bestGain = gain; bestL = li; }\n            }\n            init2[pos] = bestL;\n            usedLocal[bestL] = 1;\n        }\n\n        // init3: star around best seed at a center\n        int bestLocal = localSorted[0];\n        int centerPos = centers.empty() ? posOrder[0] : centers[rng.nextInt((int)centers.size())];\n        vector<int> init3(P, -1);\n        vector<char> used3(P, 0);\n        init3[centerPos] = bestLocal;\n        used3[bestLocal] = 1;\n\n        // fill neighbors of center by best affinity\n        for (int nb : neigh[centerPos]) {\n            int best = -1;\n            double bestS = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double s = w[bestLocal][li] + 0.001 * localImportance(li);\n                if (s > bestS) { bestS = s; best = li; }\n            }\n            if (best != -1) { init3[nb] = best; used3[best] = 1; }\n        }\n        // fill remaining by greedy on existing neighbors\n        for (int pos = 0; pos < P; pos++) {\n            if (init3[pos] != -1) continue;\n            int best = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init3[nb] != -1) gain += w[li][init3[nb]];\n                gain += 0.001 * localImportance(li);\n                if (gain > bestGain) { bestGain = gain; best = li; }\n            }\n            init3[pos] = best;\n            used3[best] = 1;\n        }\n\n        vector<vector<int>> inits = {init0, init2, init3, init1};\n\n        // ---- 4) Run SA on each init within time ----\n        double bestObj = -1e100;\n        vector<int> bestPerm = init0;\n\n        for (int r = 0; r < (int)inits.size(); r++) {\n            TimePoint nowR = Clock::now();\n            if (nowR >= turnEnd) break;\n            int left = (int)inits.size() - r;\n            double remSec = chrono::duration<double>(turnEnd - nowR).count();\n            TimePoint endR = nowR + chrono::duration_cast<Clock::duration>(chrono::duration<double>(remSec / left));\n            auto res = runSA(inits[r], w, endR);\n            if (res.first > bestObj) {\n                bestObj = res.first;\n                bestPerm = std::move(res.second);\n            }\n        }\n\n        // ---- Output ----\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = id(i, j);\n                int localIdx = bestPerm[pos];\n                int globalIdx = globOfLocal[localIdx];\n                if (j) cout << ' ';\n                cout << globalIdx;\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        // ---- Next generation ----\n        readSeeds();\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int dx4[4] = {0, 1, 0, -1}; // dir: 0=R,1=D,2=L,3=U\nstatic const int dy4[4] = {1, 0, -1, 0};\n\nstruct Leaf {\n    int len;      // edge length from root\n    int dir;      // 0..3\n    bool hold;    // holding takoyaki\n};\n\nstatic inline int ang_dist(int a, int b) {\n    int d = (a - b + 4) % 4;\n    return min(d, 4 - d);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    vector<vector<unsigned char>> cur(N, vector<unsigned char>(N, 0));\n    vector<vector<unsigned char>> target(N, vector<unsigned char>(N, 0));\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        cur[i][j] = (s[i][j] == '1');\n        target[i][j] = (t[i][j] == '1');\n    }\n\n    // Surplus: cur=1,target=0 (we want to pick from here)\n    // Deficit: cur=0,target=1 (we want to place here)\n    vector<vector<unsigned char>> isSur(N, vector<unsigned char>(N, 0));\n    vector<vector<unsigned char>> isDef(N, vector<unsigned char>(N, 0));\n\n    long long surCount = 0, defCount = 0;\n    long long sumSurX = 0, sumSurY = 0, sumDefX = 0, sumDefY = 0;\n\n    for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n        if (cur[x][y] && !target[x][y]) {\n            isSur[x][y] = 1;\n            surCount++;\n            sumSurX += x; sumSurY += y;\n        } else if (!cur[x][y] && target[x][y]) {\n            isDef[x][y] = 1;\n            defCount++;\n            sumDefX += x; sumDefY += y;\n        }\n    }\n\n    auto inside = [&](int x, int y) -> bool {\n        return (0 <= x && x < N && 0 <= y && y < N);\n    };\n\n    // Arm design: star with V' = V (>=5 by constraints).\n    int Vp = V;\n    int K = Vp - 1; // number of leaves\n    vector<Leaf> leaves(K);\n    for (int i = 0; i < K; i++) {\n        leaves[i].len = i + 1; // distinct lengths => leaves never point to same cell\n        leaves[i].dir = 0;     // initially all to the right\n        leaves[i].hold = false;\n    }\n\n    auto pointed_cell = [&](int rootx, int rooty, int len, int dir) -> pair<int,int> {\n        return {rootx + dx4[dir] * len, rooty + dy4[dir] * len};\n    };\n\n    auto can_pick = [&](int x, int y) -> bool {\n        return inside(x, y) && isSur[x][y];\n    };\n    auto can_place = [&](int x, int y) -> bool {\n        return inside(x, y) && isDef[x][y];\n    };\n\n    auto has_any_target_dir = [&](const Leaf &lf, int rootx, int rooty) -> bool {\n        for (int d = 0; d < 4; d++) {\n            auto [x, y] = pointed_cell(rootx, rooty, lf.len, d);\n            if (lf.hold) { if (can_place(x, y)) return true; }\n            else { if (can_pick(x, y)) return true; }\n        }\n        return false;\n    };\n\n    auto can_act_immediately = [&](const Leaf &lf, int rootx, int rooty) -> bool {\n        // Rotation allowed per turn: '.', 'L', 'R'\n        for (int rot = 0; rot < 3; rot++) {\n            int nd = lf.dir;\n            if (rot == 1) nd = (nd + 3) % 4;\n            else if (rot == 2) nd = (nd + 1) % 4;\n            auto [x, y] = pointed_cell(rootx, rooty, lf.len, nd);\n            if (lf.hold) { if (can_place(x, y)) return true; }\n            else { if (can_pick(x, y)) return true; }\n        }\n        return false;\n    };\n\n    auto decide_rot_and_action = [&](const Leaf &lf, int rootx, int rooty) -> pair<char,bool> {\n        // Prefer immediate action, lowest rotation cost.\n        struct Opt { char rot; int nd; bool act; int cost; };\n        Opt opts[3];\n        for (int rot = 0; rot < 3; rot++) {\n            char rc = '.';\n            int nd = lf.dir;\n            if (rot == 1) { rc = 'L'; nd = (nd + 3) % 4; }\n            else if (rot == 2) { rc = 'R'; nd = (nd + 1) % 4; }\n            auto [x, y] = pointed_cell(rootx, rooty, lf.len, nd);\n            bool act = lf.hold ? can_place(x, y) : can_pick(x, y);\n            int cost = (rc == '.') ? 0 : 1;\n            opts[rot] = {rc, nd, act, cost};\n        }\n        int bestIdx = -1;\n        for (int i = 0; i < 3; i++) if (opts[i].act) {\n            if (bestIdx == -1 || opts[i].cost < opts[bestIdx].cost) bestIdx = i;\n        }\n        if (bestIdx != -1) return {opts[bestIdx].rot, true};\n\n        // Otherwise rotate toward some direction that would be useful.\n        vector<int> targetDirs;\n        for (int d = 0; d < 4; d++) {\n            auto [x, y] = pointed_cell(rootx, rooty, lf.len, d);\n            if (lf.hold) { if (can_place(x, y)) targetDirs.push_back(d); }\n            else { if (can_pick(x, y)) targetDirs.push_back(d); }\n        }\n        if (targetDirs.empty()) return {'.', false};\n\n        int best = 0;\n        int bestDist = INT_MAX, bestCost = INT_MAX;\n        for (int i = 0; i < 3; i++) {\n            int nd = opts[i].nd;\n            int md = INT_MAX;\n            for (int td : targetDirs) md = min(md, ang_dist(nd, td));\n            if (md < bestDist || (md == bestDist && opts[i].cost < bestCost)) {\n                bestDist = md;\n                bestCost = opts[i].cost;\n                best = i;\n            }\n        }\n        return {opts[best].rot, false};\n    };\n\n    auto holding_count = [&]() -> int {\n        int c = 0;\n        for (auto &lf : leaves) if (lf.hold) c++;\n        return c;\n    };\n\n    // Decide initial root position (centroid of mismatches, else center).\n    int rx = N / 2, ry = N / 2;\n    long long needCount = surCount + defCount;\n    if (needCount > 0) {\n        long long sumX = sumSurX + sumDefX;\n        long long sumY = sumSurY + sumDefY;\n        rx = (int)(sumX / needCount);\n        ry = (int)(sumY / needCount);\n        rx = min(max(rx, 0), N - 1);\n        ry = min(max(ry, 0), N - 1);\n    }\n    const int initRx = rx, initRy = ry; // IMPORTANT: output must use initial root position.\n\n    // Move candidates\n    const char mvChar[5] = {'.','U','D','L','R'};\n    const int mvDx[5] = {0,-1,1,0,0};\n    const int mvDy[5] = {0,0,0,-1,1};\n\n    vector<string> ops;\n    ops.reserve(100000);\n\n    int noActStreak = 0;\n    bool focusMode = false;\n    int focusRx = rx, focusRy = ry;\n\n    auto update_focus = [&]() {\n        focusMode = false;\n        bool wantDef = (holding_count() > 0);\n\n        vector<int> availLens;\n        availLens.reserve(K);\n        for (auto &lf : leaves) {\n            if (wantDef) { if (lf.hold) availLens.push_back(lf.len); }\n            else { if (!lf.hold) availLens.push_back(lf.len); }\n        }\n        if (availLens.empty()) return;\n\n        int bestCellDist = INT_MAX;\n        int tx = -1, ty = -1;\n        for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n            if (wantDef) { if (!isDef[x][y]) continue; }\n            else { if (!isSur[x][y]) continue; }\n            int d = abs(rx - x) + abs(ry - y);\n            if (d < bestCellDist) { bestCellDist = d; tx = x; ty = y; }\n        }\n        if (tx < 0) return;\n\n        int bestDist = INT_MAX;\n        int bestRxx = rx, bestRyy = ry;\n        for (int L : availLens) {\n            for (int d = 0; d < 4; d++) {\n                int rxx = tx - dx4[d] * L;\n                int ryy = ty - dy4[d] * L;\n                if (!inside(rxx, ryy)) continue;\n                int dist = abs(rx - rxx) + abs(ry - ryy);\n                if (dist < bestDist) {\n                    bestDist = dist;\n                    bestRxx = rxx; bestRyy = ryy;\n                }\n            }\n        }\n        focusMode = true;\n        focusRx = bestRxx;\n        focusRy = bestRyy;\n    };\n\n    const int TURN_LIMIT = 100000;\n\n    for (int turn = 0; turn < TURN_LIMIT; turn++) {\n        if (surCount == 0 && defCount == 0) break;\n\n        if (!focusMode && noActStreak > 40) update_focus();\n\n        long long needCnt = surCount + defCount;\n        long long sumNeedX = sumSurX + sumDefX;\n        long long sumNeedY = sumSurY + sumDefY;\n\n        auto eval_move = [&](int mv) -> long long {\n            int nrx = rx + mvDx[mv], nry = ry + mvDy[mv];\n            if (!inside(nrx, nry)) return LLONG_MIN / 4;\n\n            if (focusMode) {\n                int before = abs(rx - focusRx) + abs(ry - focusRy);\n                int after  = abs(nrx - focusRx) + abs(nry - focusRy);\n                long long prog = before - after;\n                int imm = 0;\n                for (auto &lf : leaves) if (can_act_immediately(lf, nrx, nry)) imm++;\n                return prog * 100000 + imm * 1000;\n            } else {\n                int imm = 0, pot = 0;\n                for (auto &lf : leaves) {\n                    if (can_act_immediately(lf, nrx, nry)) imm++;\n                    if (has_any_target_dir(lf, nrx, nry)) pot++;\n                }\n                long long centroidPenalty = 0;\n                if (needCnt > 0) {\n                    centroidPenalty =\n                        llabs(1LL * nrx * needCnt - sumNeedX) +\n                        llabs(1LL * nry * needCnt - sumNeedY);\n                }\n                return 1000000LL * imm + 1000LL * pot - centroidPenalty;\n            }\n        };\n\n        int bestMove = 0;\n        long long bestScore = LLONG_MIN;\n        for (int mv = 0; mv < 5; mv++) {\n            long long sc = eval_move(mv);\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestMove = mv;\n            }\n        }\n\n        int nrx = rx + mvDx[bestMove], nry = ry + mvDy[bestMove];\n        if (!inside(nrx, nry)) { bestMove = 0; nrx = rx; nry = ry; }\n\n        vector<char> rotCmd(K, '.');\n        vector<char> actCmd(K, '.');\n        for (int i = 0; i < K; i++) {\n            auto [rc, doP] = decide_rot_and_action(leaves[i], nrx, nry);\n            rotCmd[i] = rc;\n            actCmd[i] = doP ? 'P' : '.';\n        }\n\n        string cmd(2 * Vp, '.');\n        cmd[0] = mvChar[bestMove];\n        for (int i = 0; i < K; i++) cmd[1 + i] = rotCmd[i];\n        cmd[Vp + 0] = '.';\n        for (int i = 0; i < K; i++) cmd[Vp + 1 + i] = actCmd[i];\n\n        // Apply move\n        rx = nrx; ry = nry;\n\n        // Apply rotations\n        for (int i = 0; i < K; i++) {\n            if (rotCmd[i] == 'L') leaves[i].dir = (leaves[i].dir + 3) % 4;\n            else if (rotCmd[i] == 'R') leaves[i].dir = (leaves[i].dir + 1) % 4;\n        }\n\n        // Apply actions in increasing vertex number order (1..K)\n        int executed = 0;\n        for (int i = 0; i < K; i++) {\n            if (cmd[Vp + 1 + i] != 'P') continue;\n            auto [x, y] = pointed_cell(rx, ry, leaves[i].len, leaves[i].dir);\n\n            bool ok = false;\n            if (!leaves[i].hold) {\n                if (can_pick(x, y)) {\n                    ok = true;\n                    leaves[i].hold = true;\n                    cur[x][y] = 0;\n                    isSur[x][y] = 0;\n                    surCount--;\n                    sumSurX -= x; sumSurY -= y;\n                }\n            } else {\n                if (can_place(x, y)) {\n                    ok = true;\n                    leaves[i].hold = false;\n                    cur[x][y] = 1;\n                    isDef[x][y] = 0;\n                    defCount--;\n                    sumDefX -= x; sumDefY -= y;\n                }\n            }\n            if (!ok) {\n                // Cancel to avoid illegal output.\n                cmd[Vp + 1 + i] = '.';\n            } else {\n                executed++;\n            }\n        }\n\n        ops.push_back(std::move(cmd));\n\n        if (executed > 0) {\n            noActStreak = 0;\n            focusMode = false;\n        } else {\n            noActStreak++;\n        }\n    }\n\n    // Output design\n    cout << Vp << \"\\n\";\n    for (int u = 1; u < Vp; u++) {\n        cout << 0 << \" \" << u << \"\\n\"; // star: parent=0, length=u\n    }\n    // MUST output the INITIAL root position (not the final one)\n    cout << initRx << \" \" << initRy << \"\\n\";\n\n    // Output operations\n    for (auto &c : ops) cout << c << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed = 0) {\n        if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int l, int r) { // inclusive\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic constexpr int MAXC = 100000;\nstatic constexpr int G = 200;\nstatic constexpr int CELL = 500;              // 200 * 500 = 100000\nstatic constexpr int PERIM_LIMIT_EDGES = 800; // 800 * 500 = 400000\n\nstruct Pt {\n    int x, y;\n    int w; // +1 mackerel, -1 sardine\n};\n\nstruct Rect {\n    int x1, x2, y1, y2; // inclusive for scoring query\n};\n\nstatic inline long long rectPerimeter(const Rect& r) {\n    return 2LL * ((long long)r.x2 - r.x1 + (long long)r.y2 - r.y1);\n}\n\n// ---------------------- 2D BIT (Fenwick of vectors), static points ----------------------\nstruct BIT2D {\n    int nx = 0;\n    vector<int> xs;\n    vector<vector<int>> ys;\n    vector<vector<int>> bit; // fenwick tree per node (1-indexed)\n\n    static void bitAdd1D(vector<int>& b, int idx, int val) {\n        for (int i = idx; i < (int)b.size(); i += i & -i) b[i] += val;\n    }\n    static int bitSum1D(const vector<int>& b, int idx) {\n        int s = 0;\n        for (int i = idx; i > 0; i -= i & -i) s += b[i];\n        return s;\n    }\n\n    void build(const vector<Pt>& pts) {\n        xs.clear();\n        xs.reserve(pts.size());\n        for (auto &p : pts) xs.push_back(p.x);\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        nx = (int)xs.size();\n\n        ys.assign(nx + 1, {});\n        for (auto &p : pts) {\n            int xi = (int)(lower_bound(xs.begin(), xs.end(), p.x) - xs.begin()) + 1;\n            for (int x = xi; x <= nx; x += x & -x) ys[x].push_back(p.y);\n        }\n        bit.assign(nx + 1, {});\n        for (int x = 1; x <= nx; x++) {\n            auto &v = ys[x];\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n            bit[x].assign((int)v.size() + 1, 0);\n        }\n        for (auto &p : pts) addPoint(p.x, p.y, p.w);\n    }\n\n    void addPoint(int xval, int yval, int w) {\n        int xi = (int)(lower_bound(xs.begin(), xs.end(), xval) - xs.begin()) + 1;\n        for (int x = xi; x <= nx; x += x & -x) {\n            int yi = (int)(lower_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin()) + 1;\n            bitAdd1D(bit[x], yi, w);\n        }\n    }\n\n    int sumPrefix(int xval, int yval) const {\n        int xi = (int)(upper_bound(xs.begin(), xs.end(), xval) - xs.begin());\n        int res = 0;\n        for (int x = xi; x > 0; x -= x & -x) {\n            int yi = (int)(upper_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin());\n            res += bitSum1D(bit[x], yi);\n        }\n        return res;\n    }\n\n    int sumRect(int x1, int x2, int y1, int y2) const { // inclusive\n        if (x2 < x1 || y2 < y1) return 0;\n        int A = sumPrefix(x2, y2);\n        int B = sumPrefix(x1 - 1, y2);\n        int C = sumPrefix(x2, y1 - 1);\n        int D = sumPrefix(x1 - 1, y1 - 1);\n        return A - B - C + D;\n    }\n};\n\n// ---------------------- point-in-polygon, boundary inclusive ----------------------\nstatic inline bool onSegAxisAligned(int x, int y, int x1, int y1, int x2, int y2) {\n    if (x1 == x2) {\n        if (x != x1) return false;\n        if (y1 > y2) swap(y1, y2);\n        return y1 <= y && y <= y2;\n    } else if (y1 == y2) {\n        if (y != y1) return false;\n        if (x1 > x2) swap(x1, x2);\n        return x1 <= x && x <= x2;\n    }\n    return false;\n}\n\nstatic bool insidePolyInclusive(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (onSegAxisAligned(x, y, x1, y1, x2, y2)) return true;\n    }\n    bool in = false;\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (x1 == x2) {\n            int xv = x1;\n            int yl = min(y1, y2), yh = max(y1, y2);\n            if (yl < y && y <= yh) {\n                if (xv > x) in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int evalPolygonDiff(const vector<Pt>& pts, const vector<pair<int,int>>& poly) {\n    int s = 0;\n    for (auto &p : pts) if (insidePolyInclusive(poly, p.x, p.y)) s += p.w;\n    return s;\n}\n\nstatic long long polygonPerimeter(const vector<pair<int,int>>& poly) {\n    long long per = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        per += llabs(x1-x2) + llabs(y1-y2);\n    }\n    return per;\n}\n\nstatic bool validOrthogonalOutputBasic(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n    if (m < 4 || m > 1000) return false;\n\n    // distinct vertices\n    {\n        vector<pair<int,int>> tmp = poly;\n        sort(tmp.begin(), tmp.end());\n        auto it = unique(tmp.begin(), tmp.end());\n        if (it != tmp.end()) return false;\n    }\n\n    for (auto [x,y] : poly) {\n        if (x < 0 || x > MAXC || y < 0 || y > MAXC) return false;\n    }\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        if (!(x1==x2 || y1==y2)) return false;\n        if (x1==x2 && y1==y2) return false;\n    }\n    if (polygonPerimeter(poly) > 400000) return false;\n    return true;\n}\n\n// ---------------------- polyomino utilities ----------------------\nstatic inline bool inCell(int x, int y) { return 0 <= x && x < G && 0 <= y && y < G; }\n\nstatic int computeBoundaryEdges(const vector<vector<unsigned char>>& occ) {\n    int edges = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) {\n        if (!inCell(x-1,y) || !occ[y][x-1]) edges++;\n        if (!inCell(x+1,y) || !occ[y][x+1]) edges++;\n        if (!inCell(x,y-1) || !occ[y-1][x]) edges++;\n        if (!inCell(x,y+1) || !occ[y+1][x]) edges++;\n    }\n    return edges;\n}\n\nstatic int computeTotalW(const vector<vector<unsigned char>>& occ, const vector<vector<int>>& wgrid) {\n    int s = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) s += wgrid[y][x];\n    return s;\n}\n\nstatic void fillHoles(vector<vector<unsigned char>>& occ) {\n    vector<vector<unsigned char>> vis(G, vector<unsigned char>(G, 0));\n    deque<pair<int,int>> dq;\n\n    auto pushIf = [&](int x, int y) {\n        if (!inCell(x,y)) return;\n        if (vis[y][x]) return;\n        if (occ[y][x]) return;\n        vis[y][x] = 1;\n        dq.push_back({x,y});\n    };\n\n    for (int x = 0; x < G; x++) { pushIf(x,0); pushIf(x,G-1); }\n    for (int y = 0; y < G; y++) { pushIf(0,y); pushIf(G-1,y); }\n\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n    while (!dq.empty()) {\n        auto [x,y] = dq.front(); dq.pop_front();\n        for (int k = 0; k < 4; k++) pushIf(x+dx4[k], y+dy4[k]);\n    }\n\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) {\n        if (!occ[y][x] && !vis[y][x]) occ[y][x] = 1;\n    }\n}\n\nstatic void pruneNegativeLeaves(vector<vector<unsigned char>>& occ, const vector<vector<int>>& wgrid) {\n    vector<vector<int>> deg(G, vector<int>(G, 0));\n    int cells = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) {\n        cells++;\n        int d = 0;\n        if (inCell(x-1,y) && occ[y][x-1]) d++;\n        if (inCell(x+1,y) && occ[y][x+1]) d++;\n        if (inCell(x,y-1) && occ[y-1][x]) d++;\n        if (inCell(x,y+1) && occ[y+1][x]) d++;\n        deg[y][x] = d;\n    }\n\n    deque<pair<int,int>> q;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) {\n        if (occ[y][x] && wgrid[y][x] < 0 && deg[y][x] <= 1) q.push_back({x,y});\n    }\n\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n\n    while (!q.empty()) {\n        auto [x,y] = q.front(); q.pop_front();\n        if (!occ[y][x]) continue;\n        if (wgrid[y][x] >= 0) continue;\n        if (deg[y][x] > 1) continue;\n        if (cells <= 1) break;\n\n        // remove\n        occ[y][x] = 0;\n        cells--;\n\n        for (int k = 0; k < 4; k++) {\n            int nx = x + dx4[k], ny = y + dy4[k];\n            if (!inCell(nx,ny) || !occ[ny][nx]) continue;\n            deg[ny][nx]--;\n            if (wgrid[ny][nx] < 0 && deg[ny][nx] <= 1) q.push_back({nx,ny});\n        }\n    }\n}\n\nstruct Polyomino {\n    vector<vector<unsigned char>> occ; // [y][x]\n    int totalW = 0;\n    int boundaryEdges = 0;\n};\n\nstatic Polyomino greedyExpandPolyomino(const vector<vector<int>>& wgrid,\n                                      vector<vector<unsigned char>> occInit) {\n    Polyomino P;\n    P.occ = std::move(occInit);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n\n    vector<vector<unsigned char>> isCand(G, vector<unsigned char>(G, 0));\n\n    struct Node { int key; int x,y; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.key < b.key; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto sharedCount = [&](int x, int y)->int{\n        int s = 0;\n        if (inCell(x-1,y) && P.occ[y][x-1]) s++;\n        if (inCell(x+1,y) && P.occ[y][x+1]) s++;\n        if (inCell(x,y-1) && P.occ[y-1][x]) s++;\n        if (inCell(x,y+1) && P.occ[y+1][x]) s++;\n        return s;\n    };\n    auto deltaEdges = [&](int x, int y)->int{\n        int sh = sharedCount(x,y);\n        return 4 - 2*sh;\n    };\n    auto keyOf = [&](int x, int y)->int{\n        int dw = wgrid[y][x];\n        int de = deltaEdges(x,y);\n        return dw * 1000 - de * 35;\n    };\n    auto pushCandidate = [&](int x, int y){\n        if (!inCell(x,y)) return;\n        if (P.occ[y][x]) return;\n        if (isCand[y][x]) return;\n        isCand[y][x] = 1;\n        pq.push(Node{keyOf(x,y), x, y});\n    };\n\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (P.occ[y][x]) {\n        pushCandidate(x-1,y);\n        pushCandidate(x+1,y);\n        pushCandidate(x,y-1);\n        pushCandidate(x,y+1);\n    }\n\n    while (!pq.empty()) {\n        auto nd = pq.top(); pq.pop();\n        int x = nd.x, y = nd.y;\n        if (!isCand[y][x]) continue;\n        if (P.occ[y][x]) { isCand[y][x] = 0; continue; }\n\n        int kNow = keyOf(x,y);\n        if (kNow != nd.key) { pq.push(Node{kNow,x,y}); continue; }\n\n        int dw = wgrid[y][x];\n        int de = deltaEdges(x,y);\n        if (P.boundaryEdges + de > PERIM_LIMIT_EDGES) { isCand[y][x] = 0; continue; }\n\n        bool accept = false;\n        if (dw > 0) accept = true;\n        else if (dw == 0 && de < 0) accept = true;\n        else if (dw >= -2 && de <= -2) accept = true;\n        if (!accept) { isCand[y][x] = 0; continue; }\n\n        P.occ[y][x] = 1;\n        isCand[y][x] = 0;\n        P.totalW += dw;\n        P.boundaryEdges += de;\n\n        pushCandidate(x-1,y);\n        pushCandidate(x+1,y);\n        pushCandidate(x,y-1);\n        pushCandidate(x,y+1);\n\n        if (P.boundaryEdges >= PERIM_LIMIT_EDGES) break;\n    }\n\n    fillHoles(P.occ);\n    pruneNegativeLeaves(P.occ, wgrid);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n    return P;\n}\n\nstatic bool collinearAxis(const pair<int,int>& a, const pair<int,int>& b, const pair<int,int>& c) {\n    return (a.first == b.first && b.first == c.first) || (a.second == b.second && b.second == c.second);\n}\n\nstatic vector<pair<int,int>> compressCollinearCyclic(vector<pair<int,int>> v) {\n    // remove consecutive duplicates if any\n    vector<pair<int,int>> w;\n    for (auto &p : v) {\n        if (w.empty() || w.back() != p) w.push_back(p);\n    }\n    v.swap(w);\n    if (v.size() >= 2 && v.front() == v.back()) v.pop_back();\n\n    bool changed = true;\n    while (changed && v.size() >= 4) {\n        changed = false;\n        int n = (int)v.size();\n        vector<char> del(n, 0);\n        for (int i = 0; i < n; i++) {\n            int ip = (i - 1 + n) % n;\n            int in = (i + 1) % n;\n            if (collinearAxis(v[ip], v[i], v[in])) del[i] = 1;\n        }\n        int cnt = 0;\n        for (int i = 0; i < n; i++) if (!del[i]) cnt++;\n        if (cnt < n && cnt >= 4) {\n            vector<pair<int,int>> nv;\n            nv.reserve(cnt);\n            for (int i = 0; i < n; i++) if (!del[i]) nv.push_back(v[i]);\n            v.swap(nv);\n            changed = true;\n        }\n    }\n    return v;\n}\n\n// Robust boundary extraction using directed boundary edges CCW (interior on left)\nstatic vector<pair<int,int>> extractBoundaryPolygon(const vector<vector<unsigned char>>& occ) {\n    const int W = G + 1;\n    const int H = G + 1;\n    const int V = W * H;\n\n    auto vid = [&](int x, int y)->int{ return y * W + x; };\n    auto vxy = [&](int id)->pair<int,int>{ return {id % W, id / W}; };\n\n    vector<int> nxt(V, -1);\n    vector<char> hasOut(V, 0);\n\n    auto cellOcc = [&](int x, int y)->bool{\n        if (!inCell(x,y)) return false;\n        return occ[y][x] != 0;\n    };\n    auto addEdge = [&](int x1,int y1,int x2,int y2){\n        int a = vid(x1,y1);\n        int b = vid(x2,y2);\n        if (nxt[a] == -1) {\n            nxt[a] = b;\n            hasOut[a] = 1;\n        }\n    };\n\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) {\n        if (!cellOcc(x, y-1)) addEdge(x, y, x+1, y);         // bottom\n        if (!cellOcc(x+1, y)) addEdge(x+1, y, x+1, y+1);     // right\n        if (!cellOcc(x, y+1)) addEdge(x+1, y+1, x, y+1);     // top\n        if (!cellOcc(x-1, y)) addEdge(x, y+1, x, y);         // left\n    }\n\n    int start = -1;\n    for (int id = 0; id < V; id++) if (hasOut[id]) {\n        if (start == -1) start = id;\n        else {\n            auto [x1,y1] = vxy(id);\n            auto [x0,y0] = vxy(start);\n            if (y1 < y0 || (y1 == y0 && x1 < x0)) start = id;\n        }\n    }\n    if (start == -1) {\n        return {{0,0},{1,0},{1,1},{0,1}};\n    }\n\n    vector<pair<int,int>> gridPath;\n    gridPath.reserve(4000);\n    int cur = start;\n    for (int steps = 0; steps < 500000; steps++) {\n        gridPath.push_back(vxy(cur));\n        int to = nxt[cur];\n        if (to == -1) break;\n        cur = to;\n        if (cur == start) break;\n    }\n    if (gridPath.size() < 4) {\n        // fallback: single occupied cell box\n        int fx=-1, fy=-1;\n        for (int y = 0; y < G && fy < 0; y++)\n            for (int x = 0; x < G; x++) if (occ[y][x]) { fx=x; fy=y; break; }\n        int x0 = fx * CELL, y0 = fy * CELL;\n        int x1 = (fx + 1) * CELL, y1 = (fy + 1) * CELL;\n        return {{x0,y0},{x1,y0},{x1,y1},{x0,y1}};\n    }\n\n    // Convert to coordinates and compress collinear\n    vector<pair<int,int>> poly;\n    poly.reserve(gridPath.size());\n    for (auto [gx,gy] : gridPath) poly.push_back({gx * CELL, gy * CELL});\n    poly = compressCollinearCyclic(poly);\n    return poly;\n}\n\nstatic bool containsAnyRect(const vector<Pt>& pts, const Rect& r) {\n    for (auto &p : pts) {\n        if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n    for (int i = 0; i < 2*N; i++) {\n        int x,y; cin >> x >> y;\n        pts.push_back(Pt{x,y,(i < N ? +1 : -1)});\n    }\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift rng(seed);\n\n    auto startTime = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]()->double{\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - startTime).count();\n    };\n\n    // Grid weights\n    vector<vector<int>> wgrid(G, vector<int>(G, 0));\n    auto cellIndex = [&](int v)->int{\n        int idx = v / CELL;\n        if (idx >= G) idx = G-1;\n        return idx;\n    };\n    for (auto &p : pts) {\n        int gx = cellIndex(p.x);\n        int gy = cellIndex(p.y);\n        wgrid[gy][gx] += p.w;\n    }\n\n    // Best grid rectangle (max sum subrectangle) O(G^3)\n    int bestSum = INT_MIN;\n    int bestL=0,bestR=0,bestB=0,bestT=0;\n    vector<int> colSum(G);\n    for (int L = 0; L < G; L++) {\n        fill(colSum.begin(), colSum.end(), 0);\n        for (int R = L; R < G; R++) {\n            for (int y = 0; y < G; y++) colSum[y] += wgrid[y][R];\n            int cur = 0, curStart = 0;\n            int localBest = INT_MIN, localB = 0, localT = 0;\n            for (int y = 0; y < G; y++) {\n                if (cur <= 0) { cur = colSum[y]; curStart = y; }\n                else cur += colSum[y];\n                if (cur > localBest) { localBest = cur; localB = curStart; localT = y; }\n            }\n            if (localBest > bestSum) {\n                bestSum = localBest;\n                bestL=L; bestR=R; bestB=localB; bestT=localT;\n            }\n        }\n    }\n\n    // Fast rectangle scoring\n    BIT2D bit2d;\n    bit2d.build(pts);\n    auto evalRectFast = [&](const Rect& r)->int{\n        return bit2d.sumRect(r.x1, r.x2, r.y1, r.y2);\n    };\n\n    auto rectFromGrid = [&](int L,int R,int B,int T)->Rect{\n        int x1 = L * CELL;\n        int x2 = min(MAXC, (R+1) * CELL);\n        int y1 = B * CELL;\n        int y2 = min(MAXC, (T+1) * CELL);\n        if (x2 <= x1) x2 = min(MAXC, x1+1);\n        if (y2 <= y1) y2 = min(MAXC, y1+1);\n        return Rect{x1,x2,y1,y2};\n    };\n\n    // Candidate coordinate sets for SA\n    vector<int> candX, candY;\n    candX.reserve(30000);\n    candY.reserve(30000);\n    auto addCand = [&](vector<int>& v, int c){\n        if (0 <= c && c <= MAXC) v.push_back(c);\n    };\n    addCand(candX, 0); addCand(candX, MAXC);\n    addCand(candY, 0); addCand(candY, MAXC);\n    for (int i = 0; i <= G; i++) { addCand(candX, i*CELL); addCand(candY, i*CELL); }\n    for (int i = 0; i < (int)pts.size(); i += 2) {\n        addCand(candX, pts[i].x); addCand(candX, pts[i].x-1); addCand(candX, pts[i].x+1);\n        addCand(candY, pts[i].y); addCand(candY, pts[i].y-1); addCand(candY, pts[i].y+1);\n    }\n    sort(candX.begin(), candX.end());\n    candX.erase(unique(candX.begin(), candX.end()), candX.end());\n    sort(candY.begin(), candY.end());\n    candY.erase(unique(candY.begin(), candY.end()), candY.end());\n\n    auto clampi = [&](int v){ return max(0, min(MAXC, v)); };\n\n    // Rectangle SA multi-start\n    Rect bestRect = rectFromGrid(bestL,bestR,bestB,bestT);\n    int bestRectDiff = evalRectFast(bestRect);\n\n    auto randomRectAround = [&]()->Rect{\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size()-1)];\n        int wx = rng.nextInt(500, 25000);\n        int wy = rng.nextInt(500, 25000);\n        int x1 = clampi(p.x - wx), x2 = clampi(p.x + wx);\n        int y1 = clampi(p.y - wy), y2 = clampi(p.y + wy);\n        if (x2 <= x1) x2 = min(MAXC, x1+1);\n        if (y2 <= y1) y2 = min(MAXC, y1+1);\n        return Rect{x1,x2,y1,y2};\n    };\n\n    vector<Rect> starts;\n    starts.push_back(bestRect);\n    for (int i = 0; i < 10; i++) starts.push_back(randomRectAround());\n\n    const double SA_TIME = 1.15;\n    const double T0 = 28.0, T1 = 0.8;\n\n    for (auto st : starts) {\n        if (elapsedSec() > SA_TIME) break;\n        if (rectPerimeter(st) > 400000) continue;\n\n        Rect cur = st;\n        int curDiff = evalRectFast(cur);\n\n        while (elapsedSec() < SA_TIME) {\n            double t = elapsedSec() / SA_TIME;\n            double T = T0 * pow(T1 / T0, t);\n\n            Rect nxt = cur;\n            int side = rng.nextInt(0,3);\n            if (side == 0) {\n                int nx1 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx1 >= nxt.x2) continue;\n                nxt.x1 = nx1;\n            } else if (side == 1) {\n                int nx2 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx2 <= nxt.x1) continue;\n                nxt.x2 = nx2;\n            } else if (side == 2) {\n                int ny1 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny1 >= nxt.y2) continue;\n                nxt.y1 = ny1;\n            } else {\n                int ny2 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny2 <= nxt.y1) continue;\n                nxt.y2 = ny2;\n            }\n\n            if (rectPerimeter(nxt) > 400000) continue;\n            int nd = evalRectFast(nxt);\n            int delta = nd - curDiff;\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double prob = exp((double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) {\n                cur = nxt;\n                curDiff = nd;\n                if (curDiff > bestRectDiff) {\n                    bestRectDiff = curDiff;\n                    bestRect = cur;\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> rectPoly = {\n        {bestRect.x1, bestRect.y1},\n        {bestRect.x2, bestRect.y1},\n        {bestRect.x2, bestRect.y2},\n        {bestRect.x1, bestRect.y2}\n    };\n\n    vector<pair<int,int>> bestPoly = rectPoly;\n    int bestDiff = evalPolygonDiff(pts, bestPoly);\n\n    auto consider = [&](const vector<pair<int,int>>& poly){\n        if (!validOrthogonalOutputBasic(poly)) return;\n        int d = evalPolygonDiff(pts, poly);\n        if (d > bestDiff) {\n            bestDiff = d;\n            bestPoly = poly;\n        }\n    };\n\n    // Polyomino seed A: best grid rectangle cells\n    {\n        vector<vector<unsigned char>> occRect(G, vector<unsigned char>(G, 0));\n        for (int y = bestB; y <= bestT; y++) for (int x = bestL; x <= bestR; x++) occRect[y][x] = 1;\n        Polyomino P = greedyExpandPolyomino(wgrid, occRect);\n        if (P.boundaryEdges <= PERIM_LIMIT_EDGES) {\n            auto poly = extractBoundaryPolygon(P.occ);\n            consider(poly);\n        }\n    }\n\n    // Polyomino seeds: top-weight cells\n    vector<tuple<int,int,int>> cells; // (w, x, y)\n    cells.reserve(G*G);\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) cells.emplace_back(wgrid[y][x], x, y);\n    sort(cells.begin(), cells.end(), greater<>());\n\n    int trySeeds = 8;\n    int pool = min(40, (int)cells.size());\n    for (int s = 0; s < trySeeds; s++) {\n        int idx = (s == 0 ? 0 : rng.nextInt(0, pool-1));\n        auto [w, cx, cy] = cells[idx];\n        if (s == 0 && w <= 0) break;\n\n        vector<vector<unsigned char>> occ(G, vector<unsigned char>(G, 0));\n        occ[cy][cx] = 1;\n        Polyomino P = greedyExpandPolyomino(wgrid, occ);\n        if (P.boundaryEdges <= PERIM_LIMIT_EDGES) {\n            auto poly = extractBoundaryPolygon(P.occ);\n            consider(poly);\n        }\n        if (elapsedSec() > 1.90) break;\n    }\n\n    // If negative, output an empty tiny rectangle for score 1\n    if (bestDiff < 0) {\n        Rect empty{0,1,0,1};\n        for (int tries = 0; tries < 5000; tries++) {\n            int x1 = rng.nextInt(0, MAXC-1);\n            int y1 = rng.nextInt(0, MAXC-1);\n            Rect r{x1, x1+1, y1, y1+1};\n            if (!containsAnyRect(pts, r)) { empty = r; break; }\n        }\n        bestPoly = {{empty.x1,empty.y1},{empty.x2,empty.y1},{empty.x2,empty.y2},{empty.x1,empty.y2}};\n    }\n\n    if (!validOrthogonalOutputBasic(bestPoly)) {\n        bestPoly = {{0,0},{MAXC,0},{MAXC,MAXC},{0,MAXC}};\n    }\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto [x,y] : bestPoly) cout << x << \" \" << y << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Plan {\n    vector<Op> ops;\n    long long predW = (1LL<<62);\n    long long predH = (1LL<<62);\n    long long predScore = (1LL<<62);\n    string tag;\n};\n\nstatic inline pair<long long,long long> dims(const vector<long long>& w, const vector<long long>& h, int i, int r){\n    if(r==0) return {w[i], h[i]};\n    return {h[i], w[i]};\n}\n\nstatic inline int rot_wide_minheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=max(w,h) and height=min(w,h)\n    return (w[i] < h[i]) ? 1 : 0;\n}\nstatic inline int rot_narrow_maxheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=min(w,h) and height=max(w,h)\n    return (w[i] > h[i]) ? 1 : 0;\n}\n\nPlan make_single_row(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r = (rotMode==0 ? rot_wide_minheight(w,h,i) : rot_narrow_maxheight(w,h,i));\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'L',-1});\n        W += ww;\n        H = max(H, hh);\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_row_wide\" : \"single_row_narrow\");\n    return pl;\n}\n\nPlan make_single_col(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r;\n        if(rotMode==0){\n            // minimize width\n            r = (w[i] > h[i]) ? 1 : 0;\n        }else{\n            // minimize height (often worse for columns but add diversity)\n            r = (w[i] < h[i]) ? 1 : 0;\n        }\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'U',-1});\n        W = max(W, ww);\n        H += hh;\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_col_minW\" : \"single_col_minH\");\n    return pl;\n}\n\n// Contiguous shelf rows with width limit M (simple fallback/diversity).\nPlan make_shelf_rows_width_limit(const vector<long long>& w, const vector<long long>& h, long long M){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n\n    long long totalH = 0;\n    long long maxW = 0;\n\n    int prevRowRep = -1;\n    long long curW = 0;\n    long long curH = 0;\n    int curRep = -1;\n\n    auto close_row = [&](){\n        if(curRep==-1) return;\n        totalH += curH;\n        maxW = max(maxW, curW);\n        prevRowRep = curRep;\n        curW = 0;\n        curH = 0;\n        curRep = -1;\n    };\n\n    for(int i=0;i<N;i++){\n        // try both rotations\n        auto [w0,h0] = dims(w,h,i,0);\n        auto [w1,h1] = dims(w,h,i,1);\n        bool fit0 = (curRep==-1 ? (w0<=M || curW==0) : (curW + w0 <= M));\n        bool fit1 = (curRep==-1 ? (w1<=M || curW==0) : (curW + w1 <= M));\n\n        int r = -1;\n        if(curRep==-1){\n            // new row: choose smaller height\n            if(h0 < h1) r=0; else r=1;\n        }else{\n            if(fit0 && fit1){\n                // choose smaller resulting row height, tie by smaller width\n                long long nh0 = max(curH, h0), nh1 = max(curH, h1);\n                if(nh0 != nh1) r = (nh0 < nh1 ? 0 : 1);\n                else r = (w0 < w1 ? 0 : 1);\n            }else if(fit0) r=0;\n            else if(fit1) r=1;\n        }\n\n        if(curRep!=-1 && r==-1){\n            close_row();\n            // new row, pick smaller height\n            if(h0 < h1) r=0; else r=1;\n        }\n\n        auto [ww,hh] = dims(w,h,i,r);\n        int b = (prevRowRep==-1 ? -1 : prevRowRep);\n        pl.ops.push_back({i,r,'L',b});\n        curW += ww;\n        if(hh > curH){\n            curH = hh;\n            curRep = i;\n        }else if(curRep==-1){\n            curRep = i;\n        }\n    }\n    close_row();\n\n    pl.predW = maxW;\n    pl.predH = totalH;\n    pl.predScore = pl.predW + pl.predH;\n    pl.tag = \"shelf_rows_M=\" + to_string(M);\n    return pl;\n}\n\n// Fixed prefix headers 0..m-1 in top row, then greedy assign remaining to columns.\n// Requires each assigned rectangle width <= its column width, otherwise infeasible.\nPlan make_prefix_columns_bruteforce(const vector<long long>& w, const vector<long long>& h, int m){\n    int N = (int)w.size();\n    Plan best;\n    best.predScore = (1LL<<62);\n    if(m<=0 || m> N) return best;\n\n    int lim = 1<<m;\n    vector<int> bestHeaderRot(m,0);\n    vector<int> bestCol(N,-1), bestRot(N,0);\n\n    for(int mask=0; mask<lim; mask++){\n        vector<long long> colW(m), colH(m);\n        long long totalW = 0;\n        long long maxH = 0;\n        for(int j=0;j<m;j++){\n            int r = (mask>>j)&1;\n            auto [ww,hh] = dims(w,h,j,r);\n            colW[j]=ww; colH[j]=hh;\n            totalW += ww;\n            maxH = max(maxH, hh);\n        }\n\n        vector<int> colOf(N,-1), rotOf(N,0);\n        for(int j=0;j<m;j++){\n            colOf[j]=j;\n            rotOf[j]= (mask>>j)&1;\n        }\n\n        bool ok = true;\n        for(int i=m;i<N;i++){\n            long long bestObj = (1LL<<62);\n            int bestJ=-1, bestR=0;\n            for(int j=0;j<m;j++){\n                for(int r=0;r<=1;r++){\n                    auto [ww,hh] = dims(w,h,i,r);\n                    if(ww > colW[j]) continue;\n                    long long nh = colH[j] + hh;\n                    long long nMaxH = max(maxH, nh);\n                    long long obj = totalW + nMaxH;\n                    if(obj < bestObj || (obj==bestObj && nh < colH[bestJ] + dims(w,h,i,bestR).second)){\n                        bestObj=obj;\n                        bestJ=j; bestR=r;\n                    }\n                }\n            }\n            if(bestJ==-1){\n                ok=false; break;\n            }\n            auto [ww,hh] = dims(w,h,i,bestR);\n            colH[bestJ] += hh;\n            maxH = max(maxH, colH[bestJ]);\n            colOf[i]=bestJ;\n            rotOf[i]=bestR;\n        }\n        if(!ok) continue;\n\n        long long score = totalW + maxH;\n        if(score < best.predScore){\n            best.predScore = score;\n            best.predW = totalW;\n            best.predH = maxH;\n            best.ops.clear();\n            best.ops.reserve(N);\n\n            // build operations: headers L, others U with b = header of left column\n            // column j starts at right edge of header (j-1) (or x=0 if j=0)\n            for(int i=0;i<N;i++){\n                int r = rotOf[i];\n                if(i < m){\n                    best.ops.push_back({i,r,'L',-1});\n                }else{\n                    int cj = colOf[i];\n                    int b = (cj==0 ? -1 : (cj-1)); // header index (cj-1) because headers are 0..m-1\n                    best.ops.push_back({i,r,'U',b});\n                }\n            }\n            best.tag = \"prefix_cols_bruteforce_m=\" + to_string(m);\n        }\n    }\n    return best;\n}\n\n// Online columns: open new columns as needed/beneficial. Columns are disjoint by enforcing width<=colWidth.\nPlan make_online_columns(const vector<long long>& w, const vector<long long>& h,\n                         long long openBias, int headerMode, std::mt19937_64* rng = nullptr)\n{\n    int N = (int)w.size();\n    struct Col{ long long W,H; int headerIdx; };\n    vector<Col> cols;\n    vector<Op> ops;\n    ops.reserve(N);\n\n    long long totalW = 0;\n    long long maxH = 0;\n\n    auto chooseHeaderRot = [&](int i)->int{\n        if(headerMode==0) return rot_wide_minheight(w,h,i);\n        else return rot_narrow_maxheight(w,h,i);\n    };\n\n    for(int i=0;i<N;i++){\n        if(cols.empty()){\n            int r = chooseHeaderRot(i);\n            auto [ww,hh] = dims(w,h,i,r);\n            cols.push_back({ww,hh,i});\n            totalW += ww;\n            maxH = max(maxH, hh);\n            ops.push_back({i,r,'L',-1});\n            continue;\n        }\n\n        // best existing placement\n        long long bestObj = (1LL<<62);\n        int bestC = -1, bestR = 0;\n        for(int c=0;c<(int)cols.size();c++){\n            for(int r=0;r<=1;r++){\n                auto [ww,hh] = dims(w,h,i,r);\n                if(ww > cols[c].W) continue;\n                long long nh = cols[c].H + hh;\n                long long nMaxH = max(maxH, nh);\n                long long obj = totalW + nMaxH;\n                if(obj < bestObj){\n                    bestObj = obj;\n                    bestC = c;\n                    bestR = r;\n                }else if(obj == bestObj && rng){\n                    // random tie-break to diversify\n                    if(((*rng)() & 7ULL)==0ULL){\n                        bestC = c;\n                        bestR = r;\n                    }\n                }\n            }\n        }\n\n        // open new column option (always feasible)\n        int hr = chooseHeaderRot(i);\n        auto [wNew,hNew] = dims(w,h,i,hr);\n        long long openObj = (totalW + wNew) + max(maxH, hNew) + openBias;\n\n        bool doOpen = false;\n        if(bestC==-1) doOpen = true;\n        else if(openObj < bestObj) doOpen = true;\n\n        if(doOpen){\n            cols.push_back({wNew,hNew,i});\n            totalW += wNew;\n            maxH = max(maxH, hNew);\n            ops.push_back({i,hr,'L',-1});\n        }else{\n            auto [ww,hh] = dims(w,h,i,bestR);\n            cols[bestC].H += hh;\n            maxH = max(maxH, cols[bestC].H);\n            int b = (bestC==0 ? -1 : cols[bestC-1].headerIdx);\n            ops.push_back({i,bestR,'U',b});\n        }\n    }\n\n    Plan pl;\n    pl.ops = std::move(ops);\n    pl.predW = totalW;\n    pl.predH = maxH;\n    pl.predScore = totalW + maxH;\n    pl.tag = string(\"online_cols_bias=\") + to_string(openBias) + (headerMode==0 ? \"_wide\" : \"_narrow\");\n    return pl;\n}\n\nstatic uint64_t hash_plan_ops(const vector<Op>& ops){\n    // lightweight hash to drop exact duplicates\n    uint64_t x = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v){\n        x ^= v;\n        x *= 1099511628211ULL;\n    };\n    for(const auto& op: ops){\n        mix((uint64_t)op.p);\n        mix((uint64_t)op.r);\n        mix((uint64_t)op.d);\n        mix((uint64_t)(op.b + 2)); // shift\n    }\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    cin >> N >> T >> sigma;\n    vector<long long> w(N), h(N);\n    for(int i=0;i<N;i++) cin >> w[i] >> h[i];\n\n    mt19937_64 rng(123456789ULL);\n\n    vector<Plan> plans;\n\n    // Baselines\n    plans.push_back(make_single_row(w,h,0));\n    plans.push_back(make_single_row(w,h,1));\n    plans.push_back(make_single_col(w,h,0));\n    plans.push_back(make_single_col(w,h,1));\n\n    // Shelf row variants (contiguous), based on area scale\n    long double area = 0;\n    for(int i=0;i<N;i++) area += (long double)w[i] * (long double)h[i];\n    long long base = (long long) llround(sqrt((long double)max((long double)1.0, area)));\n    vector<long long> factors = {6,8,10,12,14,17,20,24,30,40};\n    for(long long f : factors){\n        long long M = max(1LL, base * f / 10);\n        plans.push_back(make_shelf_rows_width_limit(w,h,M));\n    }\n\n    // Prefix-columns brute force for m<=12\n    int Mmax = min(N, 12);\n    for(int m=2;m<=Mmax;m++){\n        Plan pl = make_prefix_columns_bruteforce(w,h,m);\n        if(pl.predScore < (1LL<<61)) plans.push_back(std::move(pl));\n    }\n\n    // Online columns with several biases (wide/narrow)\n    long long scale = max(10000LL, sigma * 5);\n    vector<long long> biases = {-4*scale, -2*scale, -scale, 0, scale, 2*scale, 4*scale};\n    for(long long b : biases){\n        plans.push_back(make_online_columns(w,h,b,0,nullptr));\n        plans.push_back(make_online_columns(w,h,b,1,nullptr));\n    }\n\n    // Additional randomized online plans to increase diversity\n    for(int it=0; it<800; it++){\n        long long b = (long long)((int64_t)(rng()% (uint64_t)(8*scale+1)) - (int64_t)(4*scale));\n        int headerMode = (rng()&1ULL) ? 0 : 1;\n        plans.push_back(make_online_columns(w,h,b,headerMode,&rng));\n    }\n\n    // Sort by predicted score and drop duplicates\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b){\n        if(a.predScore != b.predScore) return a.predScore < b.predScore;\n        return a.tag < b.tag;\n    });\n\n    vector<Plan> uniq;\n    uniq.reserve(plans.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(plans.size()*2);\n\n    for(auto &pl : plans){\n        if((int)pl.ops.size() != N) continue;\n        uint64_t hv = hash_plan_ops(pl.ops);\n        if(seen.insert(hv).second){\n            uniq.push_back(std::move(pl));\n            if((int)uniq.size() >= 500) break; // enough diversity\n        }\n    }\n\n    // Interactive loop: output T plans (best first; then cycle through remaining/random-like ones)\n    for(int t=0;t<T;t++){\n        const Plan* pl;\n        if(t < (int)uniq.size()) pl = &uniq[t];\n        else pl = &uniq[t % (int)uniq.size()];\n\n        cout << pl->ops.size() << '\\n';\n        for(const auto& op : pl->ops){\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        long long Wp, Hp;\n        if(!(cin >> Wp >> Hp)) break; // safety for non-interactive runs\n        // We do not adapt online in this simple solver.\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 1000;\nstatic const uint8_t INF8 = 255;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Bits {\n    static constexpr int W = (MAXN + 63) / 64; // 16\n    array<uint64_t, W> a{};\n    void reset() { a.fill(0); }\n    void set(int i) { a[i >> 6] |= 1ULL << (i & 63); }\n    bool test(int i) const { return (a[i >> 6] >> (i & 63)) & 1ULL; }\n    bool any() const {\n        for (auto x : a) if (x) return true;\n        return false;\n    }\n};\n\nstatic inline int popcount_and(const Bits &x, const Bits &y) {\n    int s = 0;\n    for (int i = 0; i < Bits::W; i++) s += __builtin_popcountll(x.a[i] & y.a[i]);\n    return s;\n}\nstatic inline void andnot_inplace(Bits &x, const Bits &mask) { // x &= ~mask\n    for (int i = 0; i < Bits::W; i++) x.a[i] &= ~mask.a[i];\n}\n\nstatic inline double fast01(uint64_t &x) {\n    // use upper 53 bits\n    return (x >> 11) * (1.0 / 9007199254740992.0);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    vector<bitset<MAXN>> adjbs(N);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        adjbs[u].set(v);\n        adjbs[v].set(u);\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // ------------------------------------------------------------\n    // Precompute distances up to H (truncated BFS from each node)\n    // ------------------------------------------------------------\n    vector<vector<uint8_t>> dist(N, vector<uint8_t>(N, INF8));\n    {\n        deque<int> q;\n        vector<int> dd(N);\n        for (int s = 0; s < N; s++) {\n            fill(dd.begin(), dd.end(), -1);\n            dd[s] = 0;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                int dv = dd[v];\n                if (dv > H) continue;\n                dist[s][v] = (uint8_t)dv;\n                if (dv == H) continue;\n                for (int to : adj[v]) {\n                    if (dd[to] == -1) {\n                        dd[to] = dv + 1;\n                        q.push_back(to);\n                    }\n                }\n            }\n        }\n    }\n\n    // Precompute H-ball masks/lists for coverage\n    vector<Bits> coverMask(N);\n    vector<vector<int>> coverList(N);\n    for (int s = 0; s < N; s++) {\n        coverMask[s].reset();\n        coverList[s].reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (dist[s][v] != INF8) {\n                coverMask[s].set(v);\n                coverList[s].push_back(v);\n            }\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Root selection: greedy set cover + repeated prune + local shifting\n    // ------------------------------------------------------------\n    vector<int> roots;\n    {\n        Bits uncovered;\n        uncovered.reset();\n        for (int v = 0; v < N; v++) uncovered.set(v);\n\n        while (uncovered.any()) {\n            int best = -1, bestGain = -1, bestA = 1e9;\n            for (int c = 0; c < N; c++) {\n                int gain = popcount_and(coverMask[c], uncovered);\n                if (gain > bestGain || (gain == bestGain && A[c] < bestA)) {\n                    bestGain = gain;\n                    bestA = A[c];\n                    best = c;\n                }\n            }\n            roots.push_back(best);\n            andnot_inplace(uncovered, coverMask[best]);\n        }\n\n        vector<int> coverCnt(N, 0);\n        int zeroCnt = N;\n        auto add_root = [&](int r) {\n            for (int v : coverList[r]) {\n                if (coverCnt[v] == 0) zeroCnt--;\n                coverCnt[v]++;\n            }\n        };\n        auto remove_root = [&](int r) {\n            for (int v : coverList[r]) {\n                coverCnt[v]--;\n                if (coverCnt[v] == 0) zeroCnt++;\n            }\n        };\n        for (int r : roots) add_root(r);\n\n        // prune until stable, remove high-A roots first\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            sort(roots.begin(), roots.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] > A[j];\n                return i < j;\n            });\n            for (int i = 0; i < (int)roots.size(); ) {\n                int r = roots[i];\n                bool ok = true;\n                for (int v : coverList[r]) if (coverCnt[v] == 1) { ok = false; break; }\n                if (ok) {\n                    remove_root(r);\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                } else i++;\n            }\n        }\n\n        // shift roots locally to lower beauty while keeping coverage\n        vector<char> isRoot(N, 0);\n        for (int r : roots) isRoot[r] = 1;\n\n        for (int idx = 0; idx < (int)roots.size(); idx++) {\n            int r = roots[idx];\n            vector<int> cand;\n            for (int v = 0; v < N; v++) if (dist[r][v] != INF8 && dist[r][v] <= 2) cand.push_back(v);\n            sort(cand.begin(), cand.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] < A[j];\n                return i < j;\n            });\n\n            int trials = min<int>(40, cand.size());\n            for (int t = 0; t < trials; t++) {\n                int c = cand[t];\n                if (c == r) break;\n                if (isRoot[c]) continue;\n\n                remove_root(r);\n                add_root(c);\n                if (zeroCnt == 0) {\n                    isRoot[r] = 0;\n                    isRoot[c] = 1;\n                    roots[idx] = c;\n                    r = c;\n                } else {\n                    remove_root(c);\n                    add_root(r);\n                }\n            }\n        }\n\n        // prune again\n        coverCnt.assign(N, 0);\n        zeroCnt = N;\n        for (int r : roots) add_root(r);\n        changed = true;\n        while (changed) {\n            changed = false;\n            sort(roots.begin(), roots.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] > A[j];\n                return i < j;\n            });\n            for (int i = 0; i < (int)roots.size(); ) {\n                int r = roots[i];\n                bool ok = true;\n                for (int v : coverList[r]) if (coverCnt[v] == 1) { ok = false; break; }\n                if (ok) {\n                    remove_root(r);\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                } else i++;\n            }\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Initial forest: multi-source BFS, tie-break by lower A parent\n    // ------------------------------------------------------------\n    vector<int> parent(N, -2);\n    vector<int> depth(N, (int)1e9);\n    {\n        deque<int> q;\n        for (int r : roots) {\n            parent[r] = -1;\n            depth[r] = 0;\n            q.push_back(r);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (depth[v] == H) continue;\n            for (int to : adj[v]) {\n                int nd = depth[v] + 1;\n                if (nd < depth[to]) {\n                    depth[to] = nd;\n                    parent[to] = v;\n                    q.push_back(to);\n                } else if (nd == depth[to] && parent[to] != -1 && A[v] < A[parent[to]]) {\n                    parent[to] = v;\n                }\n            }\n        }\n        for (int v = 0; v < N; v++) if (parent[v] == -2) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Children lists with O(1) erase\n    // ------------------------------------------------------------\n    vector<vector<int>> children(N);\n    vector<int> childPos(N, -1);\n\n    auto build_children = [&](){\n        for (int i = 0; i < N; i++) {\n            children[i].clear();\n            childPos[i] = -1;\n        }\n        for (int v = 0; v < N; v++) if (parent[v] != -1) {\n            int p = parent[v];\n            childPos[v] = (int)children[p].size();\n            children[p].push_back(v);\n        }\n    };\n    auto remove_child = [&](int p, int v){\n        int idx = childPos[v];\n        int last = children[p].back();\n        children[p][idx] = last;\n        childPos[last] = idx;\n        children[p].pop_back();\n        childPos[v] = -1;\n    };\n    auto add_child = [&](int p, int v){\n        childPos[v] = (int)children[p].size();\n        children[p].push_back(v);\n    };\n    build_children();\n\n    // Leaves\n    vector<int> leaves;\n    vector<int> leafPos(N, -1);\n    vector<char> inLeaves(N, 0);\n    auto make_leaf = [&](int v){\n        if (inLeaves[v]) return;\n        inLeaves[v] = 1;\n        leafPos[v] = (int)leaves.size();\n        leaves.push_back(v);\n    };\n    auto unmake_leaf = [&](int v){\n        if (!inLeaves[v]) return;\n        int idx = leafPos[v];\n        int last = leaves.back();\n        leaves[idx] = last;\n        leafPos[last] = idx;\n        leaves.pop_back();\n        inLeaves[v] = 0;\n        leafPos[v] = -1;\n    };\n    auto refresh_leaf = [&](int v){\n        if (children[v].empty()) make_leaf(v);\n        else unmake_leaf(v);\n    };\n    for (int v = 0; v < N; v++) refresh_leaf(v);\n\n    // Roots list\n    vector<int> rootsCur;\n    vector<int> rootPos(N, -1);\n    vector<char> inRoot(N, 0);\n    auto make_root = [&](int v){\n        if (inRoot[v]) return;\n        inRoot[v] = 1;\n        rootPos[v] = (int)rootsCur.size();\n        rootsCur.push_back(v);\n    };\n    auto unmake_root = [&](int v){\n        if (!inRoot[v]) return;\n        int idx = rootPos[v];\n        int last = rootsCur.back();\n        rootsCur[idx] = last;\n        rootPos[last] = idx;\n        rootsCur.pop_back();\n        inRoot[v] = 0;\n        rootPos[v] = -1;\n    };\n    for (int v = 0; v < N; v++) if (parent[v] == -1) make_root(v);\n\n    // Ancestor check (O(H))\n    auto is_ancestor = [&](int anc, int node) -> bool {\n        int cur = node;\n        for (int step = 0; step <= H + 5 && cur != -1; step++) {\n            if (cur == anc) return true;\n            cur = parent[cur];\n        }\n        return false;\n    };\n\n    // ------------------------------------------------------------\n    // Maintain subtree aggregates independent of absolute depth:\n    // subSumA[v] = sum A in subtree\n    // subHeight[v] = max distance v->desc within the tree\n    // ------------------------------------------------------------\n    vector<int> subSumA(N, 0), subHeight(N, 0);\n\n    auto recalc_node = [&](int v){\n        int sum = A[v];\n        int h = 0;\n        for (int ch : children[v]) {\n            sum += subSumA[ch];\n            h = max(h, subHeight[ch] + 1);\n        }\n        subSumA[v] = sum;\n        subHeight[v] = h;\n    };\n    auto recalc_up = [&](int v){\n        while (v != -1) {\n            int oldS = subSumA[v], oldH = subHeight[v];\n            recalc_node(v);\n            if (subSumA[v] == oldS && subHeight[v] == oldH) break;\n            v = parent[v];\n        }\n    };\n\n    auto init_sub_aggregates = [&](){\n        for (int v = 0; v < N; v++) {\n            subSumA[v] = A[v];\n            subHeight[v] = 0;\n        }\n        // compute a postorder by depth (tree depth, not graph), using current depth[] as a valid topological order\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; v++) layers[min(depth[v], H)].push_back(v);\n        for (int d = H; d >= 0; d--) {\n            for (int v : layers[d]) {\n                int p = parent[v];\n                if (p != -1) {\n                    subSumA[p] += subSumA[v];\n                    subHeight[p] = max(subHeight[p], subHeight[v] + 1);\n                }\n            }\n        }\n    };\n    init_sub_aggregates();\n\n    // Buffers for subtree traversal (only when applying a move)\n    vector<int> buf1, buf2;\n    auto collect_subtree = [&](int v, vector<int>& nodes) {\n        nodes.clear();\n        vector<int> st;\n        st.push_back(v);\n        while (!st.empty()) {\n            int x = st.back(); st.pop_back();\n            nodes.push_back(x);\n            for (int ch : children[x]) st.push_back(ch);\n        }\n    };\n\n    // Score = sum depth*A (constant offset ignored)\n    long long curScore = 0;\n    for (int v = 0; v < N; v++) curScore += 1LL * depth[v] * A[v];\n    long long bestScore = curScore;\n    vector<int> bestParent = parent;\n\n    auto potential = [&](int v) -> long long {\n        int slack = H - (depth[v] + subHeight[v]);\n        if (slack <= 0) return 0;\n        return 1LL * slack * subSumA[v];\n    };\n\n    // ------------------------------------------------------------\n    // Move: Reattach subtree v under neighbor u (may increase or decrease score)\n    // Feasibility: newDepthV + subHeight[v] <= H and edge(u,v) exists\n    // Cycle only possible if delta>0 and u is in subtree(v)\n    // ------------------------------------------------------------\n    auto apply_reattach = [&](int v, int u, int delta) {\n        long long deltaScore = 1LL * delta * subSumA[v];\n\n        int oldp = parent[v];\n        if (oldp == -1) unmake_root(v);\n        if (oldp != -1) {\n            remove_child(oldp, v);\n            refresh_leaf(oldp);\n        }\n\n        parent[v] = u;\n        add_child(u, v);\n        refresh_leaf(u);\n\n        if (delta != 0) {\n            collect_subtree(v, buf1);\n            for (int x : buf1) depth[x] += delta;\n        }\n\n        curScore += deltaScore;\n\n        if (oldp != -1) recalc_up(oldp);\n        recalc_up(u);\n    };\n\n    auto try_reattach_SA = [&](int v, int u, double T) -> bool {\n        if (u == v) return false;\n        if (!adjbs[v].test(u)) return false;\n\n        int newDepthV = depth[u] + 1;\n        if (newDepthV > H) return false;\n        if (newDepthV + subHeight[v] > H) return false;\n\n        int delta = newDepthV - depth[v];\n        if (delta > 0) {\n            if (is_ancestor(v, u)) return false; // prevent cycle\n        }\n        long long deltaScore = 1LL * delta * subSumA[v];\n\n        if (deltaScore >= 0) {\n            apply_reattach(v, u, delta);\n            return true;\n        } else {\n            // SA accept\n            uint64_t rr = rng();\n            double p = exp((double)deltaScore / T);\n            if (fast01(rr) < p) {\n                apply_reattach(v, u, delta);\n                return true;\n            }\n        }\n        return false;\n    };\n\n    auto best_deeper_neighbor = [&](int v) -> int {\n        int bestU = -1, bestD = -1;\n        int limit = H - 1 - subHeight[v];\n        for (int u : adj[v]) {\n            if (depth[u] > limit) continue;\n            int nd = depth[u] + 1;\n            if (nd <= depth[v]) continue;\n            if (is_ancestor(v, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    // ------------------------------------------------------------\n    // Move: Rotation around p->c (c child of p)\n    // deltaScore = subSumA[p] - 2*subSumA[c]\n    // Feasible if:\n    //  - if gp exists, edge(gp,c) exists\n    //  - max absolute depth of \"other part\" <= H-1 (it will be +1 after rotation)\n    // ------------------------------------------------------------\n    auto eval_rotate_gain_feasible = [&](int c) -> pair<bool,long long> {\n        int p = parent[c];\n        if (p == -1) return {false, 0};\n        int gp = parent[p];\n        if (gp != -1 && !adjbs[gp].test(c)) return {false, 0};\n\n        int maxAbsOther = depth[p]; // p itself\n        for (int o : children[p]) if (o != c) {\n            maxAbsOther = max(maxAbsOther, depth[o] + subHeight[o]);\n        }\n        if (maxAbsOther > H - 1) return {false, 0};\n\n        long long gain = 1LL * subSumA[p] - 2LL * subSumA[c];\n        return {true, gain};\n    };\n\n    auto apply_rotate = [&](int c, long long gain) {\n        int p = parent[c];\n        int gp = parent[p];\n\n        // collect nodes for depth update\n        collect_subtree(p, buf1);\n        collect_subtree(c, buf2);\n\n        remove_child(p, c);\n        refresh_leaf(p);\n\n        if (gp != -1) {\n            remove_child(gp, p);\n            refresh_leaf(gp);\n            parent[c] = gp;\n            add_child(gp, c);\n            refresh_leaf(gp);\n        } else {\n            parent[c] = -1;\n            make_root(c);\n            unmake_root(p);\n        }\n\n        parent[p] = c;\n        add_child(c, p);\n        refresh_leaf(c);\n\n        // depth updates:\n        // nodes in subtree(p): +1\n        // nodes in subtree(c): -2  (net -1 for c-subtree)\n        for (int x : buf1) depth[x] += 1;\n        for (int x : buf2) depth[x] -= 2;\n\n        curScore += gain;\n\n        recalc_up(p);\n        recalc_up(c);\n        if (gp != -1) recalc_up(gp);\n    };\n\n    auto try_rotate_SA = [&](int c, double T) -> bool {\n        auto [ok, gain] = eval_rotate_gain_feasible(c);\n        if (!ok) return false;\n        if (gain >= 0) {\n            apply_rotate(c, gain);\n            return true;\n        } else {\n            uint64_t rr = rng();\n            double p = exp((double)gain / T);\n            if (fast01(rr) < p) {\n                apply_rotate(c, gain);\n                return true;\n            }\n        }\n        return false;\n    };\n\n    // ------------------------------------------------------------\n    // Selection helpers\n    // ------------------------------------------------------------\n    vector<int> allNodes(N);\n    iota(allNodes.begin(), allNodes.end(), 0);\n\n    auto pick_best_among = [&](const vector<int>& pool, int k) -> int {\n        if (pool.empty()) return -1;\n        int best = pool[rng() % pool.size()];\n        long long bestW = potential(best);\n        for (int i = 1; i < k; i++) {\n            int v = pool[rng() % pool.size()];\n            long long w = potential(v);\n            if (w > bestW) { bestW = w; best = v; }\n        }\n        return best;\n    };\n\n    // ------------------------------------------------------------\n    // Warm-up: greedy deepening\n    // ------------------------------------------------------------\n    {\n        vector<int> ord = allNodes;\n        sort(ord.begin(), ord.end(), [&](int i, int j){\n            long long pi = potential(i), pj = potential(j);\n            if (pi != pj) return pi > pj;\n            return A[i] > A[j];\n        });\n        int tries = min(N, 300);\n        for (int t = 0; t < tries; t++) {\n            int v = ord[t];\n            for (int rep = 0; rep < 2; rep++) {\n                int u = best_deeper_neighbor(v);\n                if (u == -1) break;\n                double dummyT = 1e-9; // always accept improving\n                if (!try_reattach_SA(v, u, dummyT)) break;\n            }\n        }\n        if (curScore > bestScore) { bestScore = curScore; bestParent = parent; }\n    }\n\n    // ------------------------------------------------------------\n    // SA local search\n    // ------------------------------------------------------------\n    Timer timer;\n    const double TL = 1.95;\n    const double T0 = 50000.0;\n    const double T1 = 80.0;\n\n    while (timer.elapsed_sec() < TL) {\n        double frac = timer.elapsed_sec() / TL;\n        double T = T0 * pow(T1 / T0, frac);\n\n        uint64_t r = rng();\n        int mode = (int)(r % 100);\n\n        if (mode < 48) {\n            // Leaf deepening (mostly improving)\n            int v = pick_best_among(leaves, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) try_reattach_SA(v, u, T);\n\n        } else if (mode < 70) {\n            // General deepening (mostly improving)\n            int v = pick_best_among(allNodes, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) try_reattach_SA(v, u, T);\n\n        } else if (mode < 80) {\n            // Root merge attempt (usually improving, but SA can accept slight losses)\n            if (rootsCur.size() <= 1) continue;\n            int v = pick_best_among(rootsCur, 6);\n            if (v == -1) continue;\n            // try a few neighbors (not necessarily deeper) to restructure/merge\n            for (int rep = 0; rep < 4; rep++) {\n                int u = adj[v][rng() % adj[v].size()];\n                if (u == v) continue;\n                if (try_reattach_SA(v, u, T)) break;\n            }\n\n        } else if (mode < 92) {\n            // Random reattach for structural changes (SA)\n            int v = (int)(rng() % N);\n            int u = adj[v][rng() % adj[v].size()];\n            try_reattach_SA(v, u, T);\n\n        } else if (mode < 98) {\n            // Rotation (SA)\n            int p = (int)(rng() % N);\n            if (children[p].empty()) continue;\n            int c = children[p][rng() % children[p].size()];\n            try_rotate_SA(c, T);\n\n        } else {\n            // Height shaving: pick a root with structural height H, trace a deepest leaf, try to move it upward (SA)\n            if (rootsCur.empty()) continue;\n            int rrt = rootsCur[rng() % rootsCur.size()];\n            if (subHeight[rrt] < H) continue;\n\n            int cur = rrt;\n            // trace deepest path by subHeight\n            for (int step = 0; step < H; step++) {\n                int nxt = -1;\n                for (int ch : children[cur]) {\n                    if (subHeight[ch] + 1 == subHeight[cur]) { nxt = ch; break; }\n                }\n                if (nxt == -1) break;\n                cur = nxt;\n            }\n            int v = cur; // deepest-ish node (often leaf)\n            // try to reattach v to a shallower neighbor (reduce absolute depth)\n            int bestU = -1;\n            int bestDepth = 1e9;\n            for (int rep = 0; rep < 8; rep++) {\n                int u = adj[v][rng() % adj[v].size()];\n                if (u == v) continue;\n                int newDepthV = depth[u] + 1;\n                if (newDepthV + subHeight[v] > H) continue;\n                if (newDepthV < depth[v] && depth[u] < bestDepth) { // prefer shallower parent\n                    bestDepth = depth[u];\n                    bestU = u;\n                }\n            }\n            if (bestU != -1) try_reattach_SA(v, bestU, T);\n        }\n\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestParent = parent;\n        }\n    }\n\n    // ------------------------------------------------------------\n    // Final safety repair on bestParent (should rarely change)\n    // ------------------------------------------------------------\n    auto repair = [&](vector<int>& par){\n        // break cycles\n        vector<int> state(N, 0);\n        for (int v = 0; v < N; v++) {\n            if (state[v]) continue;\n            int cur = v;\n            while (cur != -1 && state[cur] == 0) {\n                state[cur] = 1;\n                cur = par[cur];\n            }\n            if (cur != -1 && state[cur] == 1) par[v] = -1;\n            cur = v;\n            while (cur != -1 && state[cur] == 1) {\n                state[cur] = 2;\n                cur = par[cur];\n            }\n        }\n        // parent edge exists\n        for (int v = 0; v < N; v++) {\n            if (par[v] == -1) continue;\n            if (!adjbs[v].test(par[v])) par[v] = -1;\n        }\n        // build children and depths\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) if (par[v] != -1) ch[par[v]].push_back(v);\n\n        vector<int> dep(N, -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (par[v] == -1) {\n            dep[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int to : ch[v]) {\n                dep[to] = dep[v] + 1;\n                q.push_back(to);\n            }\n        }\n        for (int v = 0; v < N; v++) if (dep[v] == -1) {\n            par[v] = -1;\n            dep[v] = 0;\n        }\n        for (int v = 0; v < N; v++) if (dep[v] > H) par[v] = -1;\n    };\n\n    repair(bestParent);\n\n    for (int i = 0; i < N; i++) {\n        cout << bestParent[i] << (i + 1 == N ? '\\n' : ' ');\n    }\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\n\nstruct Option {\n    bool valid = false;\n    int type = -1; // 0:U col, 1:D col, 2:L row, 3:R row\n    int idx = -1;  // row or col index\n    int depth = 0; // required K\n};\n\nstruct Oni {\n    int r, c;\n    array<Option,4> opt; // 0:U 1:D 2:L 3:R\n    vector<int> feasibleDirs;\n    bool fixed = false;\n};\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto t = steady_clock::now() - st;\n    return duration<double>(t).count();\n}\n\nint computeCost(const vector<Oni>& onis, const vector<int>& dir,\n                array<int,N>& U, array<int,N>& D, array<int,N>& L, array<int,N>& R) {\n    U.fill(0); D.fill(0); L.fill(0); R.fill(0);\n    for (int k = 0; k < (int)onis.size(); k++) {\n        const auto &o = onis[k];\n        const Option &op = o.opt[dir[k]];\n        // assumed valid\n        if (op.type == 0) U[op.idx] = max(U[op.idx], op.depth);\n        else if (op.type == 1) D[op.idx] = max(D[op.idx], op.depth);\n        else if (op.type == 2) L[op.idx] = max(L[op.idx], op.depth);\n        else if (op.type == 3) R[op.idx] = max(R[op.idx], op.depth);\n    }\n    int sum = 0;\n    for (int i = 0; i < N; i++) sum += U[i] + D[i] + L[i] + R[i];\n    return sum;\n}\n\nint computeCostOnly(const vector<Oni>& onis, const vector<int>& dir) {\n    array<int,N> U,D,L,R;\n    return computeCost(onis, dir, U, D, L, R);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<string> C(n);\n    for (int i = 0; i < n; i++) cin >> C[i];\n\n    // Limits based on Fukunokami positions (fixed-safe depths)\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    left_limit.fill(N);\n    right_limit.fill(N);\n    up_limit.fill(N);\n    down_limit.fill(N);\n\n    // Row limits\n    for (int i = 0; i < N; i++) {\n        int first = N, last = -1;\n        for (int j = 0; j < N; j++) if (C[i][j] == 'o') {\n            first = min(first, j);\n            last = max(last, j);\n        }\n        left_limit[i] = first; // K <= first\n        if (last == -1) right_limit[i] = N;\n        else right_limit[i] = (N - 1 - last); // K <= dist from last o to right edge\n    }\n    // Col limits\n    for (int j = 0; j < N; j++) {\n        int first = N, last = -1;\n        for (int i = 0; i < N; i++) if (C[i][j] == 'o') {\n            first = min(first, i);\n            last = max(last, i);\n        }\n        up_limit[j] = first; // K <= first\n        if (last == -1) down_limit[j] = N;\n        else down_limit[j] = (N - 1 - last);\n    }\n\n    // Gather Oni\n    vector<Oni> onis;\n    onis.reserve(2*N);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (C[i][j] != 'x') continue;\n        Oni o;\n        o.r = i; o.c = j;\n\n        // U\n        {\n            int K = i + 1;\n            if (K <= up_limit[j]) {\n                o.opt[0] = Option{true, 0, j, K};\n                o.feasibleDirs.push_back(0);\n            }\n        }\n        // D\n        {\n            int K = N - i;\n            if (K <= down_limit[j]) {\n                o.opt[1] = Option{true, 1, j, K};\n                o.feasibleDirs.push_back(1);\n            }\n        }\n        // L\n        {\n            int K = j + 1;\n            if (K <= left_limit[i]) {\n                o.opt[2] = Option{true, 2, i, K};\n                o.feasibleDirs.push_back(2);\n            }\n        }\n        // R\n        {\n            int K = N - j;\n            if (K <= right_limit[i]) {\n                o.opt[3] = Option{true, 3, i, K};\n                o.feasibleDirs.push_back(3);\n            }\n        }\n\n        // Guaranteed at least one feasible direction by problem statement\n        if (o.feasibleDirs.empty()) {\n            // Fallback (should not happen)\n            // But to avoid crashing: assign Up with K=1 (unsafe), still.\n            o.feasibleDirs.push_back(0);\n            o.opt[0] = Option{true,0,j,1};\n        }\n        if (o.feasibleDirs.size() == 1) o.fixed = true;\n\n        onis.push_back(o);\n    }\n\n    int M = (int)onis.size();\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    std::mt19937_64 rng(seed);\n\n    auto randInt = [&](int lo, int hi)->int{ // inclusive\n        std::uniform_int_distribution<int> dist(lo, hi);\n        return dist(rng);\n    };\n    auto randDouble = [&]()->double{\n        std::uniform_real_distribution<double> dist(0.0, 1.0);\n        return dist(rng);\n    };\n\n    // Initial assignment: minimal required depth (greedy)\n    vector<int> curDir(M, 0);\n    for (int k = 0; k < M; k++) {\n        int bestd = -1;\n        int bestK = INT_MAX;\n        // slight randomness among ties\n        vector<int> ties;\n        for (int d : onis[k].feasibleDirs) {\n            int dep = onis[k].opt[d].depth;\n            if (dep < bestK) {\n                bestK = dep;\n                ties.clear();\n                ties.push_back(d);\n            } else if (dep == bestK) {\n                ties.push_back(d);\n            }\n        }\n        bestd = ties[randInt(0, (int)ties.size()-1)];\n        curDir[k] = bestd;\n    }\n\n    int curCost = computeCostOnly(onis, curDir);\n    vector<int> bestDir = curDir;\n    int bestCost = curCost;\n\n    // Simulated annealing\n    double start = now_sec();\n    double TL = 1.90; // aim under 2s\n    const double T0 = 30.0;\n    const double T1 = 0.5;\n\n    while (true) {\n        double t = now_sec() - start;\n        if (t >= TL) break;\n        double p = t / TL;\n        double temp = T0 * (1.0 - p) + T1 * p;\n\n        int k = randInt(0, M-1);\n        if (onis[k].fixed) continue;\n\n        const auto &fds = onis[k].feasibleDirs;\n        if ((int)fds.size() <= 1) continue;\n\n        int old = curDir[k];\n        int nd = old;\n        // pick different feasible direction\n        for (int tries = 0; tries < 10; tries++) {\n            nd = fds[randInt(0, (int)fds.size()-1)];\n            if (nd != old) break;\n        }\n        if (nd == old) continue;\n\n        curDir[k] = nd;\n        int newCost = computeCostOnly(onis, curDir);\n        int delta = newCost - curCost;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(- (double)delta / temp);\n            if (randDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            curCost = newCost;\n            if (curCost < bestCost) {\n                bestCost = curCost;\n                bestDir = curDir;\n            }\n        } else {\n            curDir[k] = old;\n        }\n    }\n\n    // Final coordinate descent (greedy local improvement)\n    curDir = bestDir;\n    curCost = bestCost;\n    bool improved = true;\n    for (int it = 0; it < 30 && improved; it++) {\n        improved = false;\n        for (int k = 0; k < M; k++) {\n            if (onis[k].fixed) continue;\n            int old = curDir[k];\n            int bestd = old;\n            int bestLocalCost = curCost;\n            for (int nd : onis[k].feasibleDirs) {\n                if (nd == old) continue;\n                curDir[k] = nd;\n                int cst = computeCostOnly(onis, curDir);\n                if (cst < bestLocalCost) {\n                    bestLocalCost = cst;\n                    bestd = nd;\n                }\n            }\n            curDir[k] = old;\n            if (bestd != old) {\n                curDir[k] = bestd;\n                curCost = bestLocalCost;\n                improved = true;\n            }\n        }\n    }\n    bestDir = curDir;\n    bestCost = curCost;\n\n    // Build depths from best assignment\n    array<int,N> U,D,L,R;\n    computeCost(onis, bestDir, U, D, L, R);\n\n    // Output operations\n    vector<pair<char,int>> ans;\n    ans.reserve(2 * bestCost);\n\n    auto addRepeat = [&](char ch, int idx, int k) {\n        for (int t = 0; t < k; t++) ans.push_back({ch, idx});\n    };\n\n    // Columns: top deletions then bottom deletions\n    for (int j = 0; j < N; j++) {\n        int k = U[j];\n        if (k > 0) {\n            addRepeat('U', j, k);\n            addRepeat('D', j, k);\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        int k = D[j];\n        if (k > 0) {\n            addRepeat('D', j, k);\n            addRepeat('U', j, k);\n        }\n    }\n\n    // Rows: left deletions then right deletions\n    for (int i = 0; i < N; i++) {\n        int k = L[i];\n        if (k > 0) {\n            addRepeat('L', i, k);\n            addRepeat('R', i, k);\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        int k = R[i];\n        if (k > 0) {\n            addRepeat('R', i, k);\n            addRepeat('L', i, k);\n        }\n    }\n\n    // Safety: must be <= 4N^2\n    // (Should always hold because each Oni contributes depth<=20 and there are 40 Oni.)\n    if ((int)ans.size() > 4 * N * N) {\n        // Fallback: output nothing (would score poorly but avoid WA by too many ops).\n        // However, this should not happen.\n        ans.clear();\n    }\n\n    for (auto [ch, idx] : ans) {\n        cout << ch << \" \" << idx << \"\\n\";\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 100;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int mod) { return (int)(nextU64() % (uint64_t)mod); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline int iabs_int(int x) { return x < 0 ? -x : x; }\nstatic inline long long iabs_ll(long long x) { return x < 0 ? -x : x; }\n\nstruct Plan {\n    array<int, N> a;\n    array<int, N> b;\n};\n\nint simulate_plan(const Plan& p, int L, const array<int, N>& T, array<int, N>& cnt) {\n    cnt.fill(0);\n    int cur = 0;\n    cnt[0] = 1;\n    for (int step = 1; step < L; ++step) {\n        int x = cur;\n        cur = (cnt[x] & 1) ? p.a[x] : p.b[x];\n        ++cnt[cur];\n    }\n    int E = 0;\n    for (int i = 0; i < N; ++i) E += iabs_int(cnt[i] - T[i]);\n    return E;\n}\n\n// Kosaraju SCC on \"core nodes\", edges are a[v], b[v] (assumed to be within core for v in core)\nint scc_core(const Plan& p, const vector<int>& core, const array<char, N>& inCore,\n             array<int, N>& compOut) {\n    vector<int> nodes = core;\n    int K = (int)nodes.size();\n    if (K == 0) return 0;\n    // map node -> idx not needed; use inCore check\n    vector<vector<int>> rg(N); rg.assign(N, {});\n    vector<vector<int>> g(N);  g.assign(N, {});\n    for (int v : nodes) {\n        int to1 = p.a[v], to2 = p.b[v];\n        g[v].push_back(to1);\n        g[v].push_back(to2);\n        rg[to1].push_back(v);\n        rg[to2].push_back(v);\n    }\n    vector<char> vis(N, 0);\n    vector<int> order; order.reserve(K);\n\n    auto dfs1 = [&](auto&& self, int v) -> void {\n        vis[v] = 1;\n        for (int to : g[v]) if (inCore[to] && !vis[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int v : nodes) if (!vis[v]) dfs1(dfs1, v);\n\n    compOut.fill(-1);\n    int compCnt = 0;\n    auto dfs2 = [&](auto&& self, int v) -> void {\n        compOut[v] = compCnt;\n        for (int to : rg[v]) if (inCore[to] && compOut[to] == -1) self(self, to);\n    };\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (compOut[v] == -1) {\n            dfs2(dfs2, v);\n            ++compCnt;\n        }\n    }\n    return compCnt;\n}\n\n// Static balance objective on core:\n// incomingW[j] = sum_{i in core} T[i] * [a_i==j] + T[i] * [b_i==j]\n// want incomingW[j] ~= 2*T[j]\nstruct StaticBalance {\n    array<long long, N> D; // D[j] = incomingW[j] - 2*T[j], only meaningful on core\n    long long F = 0;       // sum |D[j]| over core\n};\n\nStaticBalance compute_static_balance(const Plan& p, const array<int, N>& T,\n                                     const vector<int>& core, const array<char, N>& inCore) {\n    array<long long, N> incoming{};\n    incoming.fill(0);\n    for (int i : core) {\n        incoming[p.a[i]] += T[i];\n        incoming[p.b[i]] += T[i];\n    }\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = incoming[j] - 2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n    return sb;\n}\n\ninline long long delta_move_edge(long long Dold, long long Dnew, int w) {\n    // Move one edge of weight w: D_old -= w, D_new += w\n    long long before = iabs_ll(Dold) + iabs_ll(Dnew);\n    long long after  = iabs_ll(Dold - w) + iabs_ll(Dnew + w);\n    return after - before;\n}\n\ninline void apply_move_edge(StaticBalance& sb, int oldDest, int newDest, int w) {\n    // assumes oldDest,newDest are in core and w>=0\n    sb.F -= iabs_ll(sb.D[oldDest]);\n    sb.D[oldDest] -= w;\n    sb.F += iabs_ll(sb.D[oldDest]);\n\n    sb.F -= iabs_ll(sb.D[newDest]);\n    sb.D[newDest] += w;\n    sb.F += iabs_ll(sb.D[newDest]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, L;\n    cin >> Nin >> L;\n    array<int, N> T{};\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    uint64_t seed = 123456789ULL;\n    for (int i = 0; i < N; ++i) seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    RNG rng(seed);\n\n    auto time_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    // Core: nodes with positive target\n    array<char, N> inCore{};\n    inCore.fill(0);\n    vector<int> core;\n    core.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        if (T[i] > 0) { inCore[i] = 1; core.push_back(i); }\n    }\n\n    // Edge case: if somehow core is empty (shouldn't happen since sum T = L), make core {0}\n    if (core.empty()) { inCore[0] = 1; core.push_back(0); }\n\n    int hub = core[0];\n    for (int v : core) if (T[v] > T[hub]) hub = v;\n\n    Plan p;\n    p.a.fill(hub);\n    p.b.fill(hub);\n\n    // ----- Initial construction: greedy best-improvement per edge on static objective -----\n    // Initialize D = -2*T on core\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = -2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n\n    // Assign edges for core nodes to reduce F\n    for (int i : core) {\n        int w = T[i];\n        for (int e = 0; e < 2; ++e) {\n            int bestJ = core[rng.nextInt((int)core.size())];\n            long long bestDelta = (1LL<<62);\n\n            // If weight is 0 (shouldn't inside core), just random to help connectivity later\n            if (w == 0) {\n                bestJ = core[rng.nextInt((int)core.size())];\n                bestDelta = 0;\n            } else {\n                for (int j : core) {\n                    // currently edge points to hub, but we are building from scratch: treat as adding w to j\n                    long long before = iabs_ll(sb.D[j]);\n                    long long after  = iabs_ll(sb.D[j] + w);\n                    long long delta = after - before;\n                    if (delta < bestDelta || (delta == bestDelta && rng.nextInt(8) == 0)) {\n                        bestDelta = delta;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            // Apply: oldDest was \"none\" (incoming 0), but our sb.D already includes only demand.\n            // So just D[bestJ] += w, update F accordingly.\n            sb.F -= iabs_ll(sb.D[bestJ]);\n            sb.D[bestJ] += w;\n            sb.F += iabs_ll(sb.D[bestJ]);\n\n            if (e == 0) p.a[i] = bestJ;\n            else p.b[i] = bestJ;\n        }\n    }\n\n    // Non-core nodes: point to hub (won't be visited if core is closed and 0 in core; if 0 not in core, it is transient)\n    for (int i = 0; i < N; ++i) if (!inCore[i]) {\n        p.a[i] = hub;\n        p.b[i] = hub;\n    }\n\n    // If 0 is not in core, ensure it enters core immediately and never referenced by core (we keep core closed)\n    if (!inCore[0]) {\n        p.a[0] = hub;\n        p.b[0] = hub;\n    }\n\n    // Recompute sb properly from plan (for correctness after our incremental build)\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Fast SA on static balance objective -----\n    // Periodically keep sorted lists of deficits\n    vector<int> core_sorted = core;\n\n    auto resort_core = [&]() {\n        core_sorted = core;\n        sort(core_sorted.begin(), core_sorted.end(), [&](int x, int y) {\n            return sb.D[x] < sb.D[y]; // more negative first (needs incoming)\n        });\n    };\n    resort_core();\n\n    // Weighted source selection among core based on T[i]\n    vector<long long> pref;\n    pref.reserve(core.size()+1);\n    auto build_pref = [&]() {\n        pref.assign(core.size()+1, 0);\n        for (int k = 0; k < (int)core.size(); ++k) {\n            pref[k+1] = pref[k] + max(1, T[core[k]]); // avoid all-zero\n        }\n    };\n    build_pref();\n\n    auto pick_core_weighted = [&]() -> int {\n        long long sum = pref.back();\n        long long r = (long long)(rng.nextU64() % (uint64_t)sum);\n        int k = (int)(upper_bound(pref.begin(), pref.end(), r) - pref.begin()) - 1;\n        if (k < 0) k = 0;\n        if (k >= (int)core.size()) k = (int)core.size()-1;\n        return core[k];\n    };\n\n    const double STATIC_END = 0.65; // seconds budget for static stage\n    long long bestF = sb.F;\n    Plan bestStatic = p;\n\n    int iter = 0;\n    while (elapsedSec() < STATIC_END && !core.empty()) {\n        ++iter;\n        if ((iter & 1023) == 0) resort_core();\n\n        int i = (rng.nextInt(100) < 75) ? pick_core_weighted() : core[rng.nextInt((int)core.size())];\n        int w = T[i];\n        int e = rng.nextInt(2);\n        int& edge = (e == 0 ? p.a[i] : p.b[i]);\n        int oldDest = edge;\n\n        // choose new destination among a small candidate set\n        int candCount = 10;\n        long long bestDelta = (1LL<<62);\n        int bestDest = oldDest;\n\n        for (int t = 0; t < candCount; ++t) {\n            int newDest;\n            if (rng.nextInt(100) < 75) {\n                // pick from most-negative (needs incoming)\n                int idx = rng.nextInt(min(20, (int)core_sorted.size()));\n                newDest = core_sorted[idx];\n            } else {\n                newDest = core[rng.nextInt((int)core.size())];\n            }\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d < bestDelta) { bestDelta = d; bestDest = newDest; }\n        }\n        if (bestDest == oldDest) continue;\n\n        // SA acceptance on static objective\n        double tcur = min(1.0, elapsedSec() / STATIC_END);\n        double temp = 2000.0 * pow(1.0 / 2000.0, tcur); // 2000 -> 1\n        bool accept = false;\n        if (bestDelta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)bestDelta / temp)) accept = true;\n\n        if (!accept) continue;\n\n        // apply\n        apply_move_edge(sb, oldDest, bestDest, w);\n        edge = bestDest;\n\n        if (sb.F < bestF) {\n            bestF = sb.F;\n            bestStatic = p;\n        }\n    }\n    p = bestStatic;\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Repair: make core strongly connected (to avoid falling into a sink SCC subset) -----\n    array<int, N> comp{};\n    int compCnt = scc_core(p, core, inCore, comp);\n    int repairRounds = 0;\n    while (compCnt > 1 && elapsedSec() < 0.90 && repairRounds < 50) {\n        ++repairRounds;\n\n        vector<int> rep(compCnt, -1);\n        for (int v : core) {\n            int c = comp[v];\n            if (rep[c] == -1 || T[v] < T[rep[c]]) rep[c] = v;\n        }\n        // connect components in a cycle using minimal-static-delta edge rewires\n        for (int c = 0; c < compCnt; ++c) {\n            int from = rep[c];\n            int to = rep[(c+1) % compCnt];\n            if (from == -1 || to == -1) continue;\n            if (p.a[from] == to || p.b[from] == to) continue;\n\n            int w = T[from];\n\n            // choose whether to replace a or b to minimize static damage\n            long long da = delta_move_edge(sb.D[p.a[from]], sb.D[to], w);\n            long long db = delta_move_edge(sb.D[p.b[from]], sb.D[to], w);\n\n            if (da <= db) {\n                int old = p.a[from];\n                apply_move_edge(sb, old, to, w);\n                p.a[from] = to;\n            } else {\n                int old = p.b[from];\n                apply_move_edge(sb, old, to, w);\n                p.b[from] = to;\n            }\n        }\n\n        // small local clean-up on static objective after rewiring\n        for (int k = 0; k < 2000; ++k) {\n            int i = pick_core_weighted();\n            int w = T[i];\n            int e = rng.nextInt(2);\n            int& edge = (e == 0 ? p.a[i] : p.b[i]);\n            int oldDest = edge;\n\n            int newDest = core[rng.nextInt((int)core.size())];\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d <= 0) {\n                apply_move_edge(sb, oldDest, newDest, w);\n                edge = newDest;\n            }\n        }\n\n        compCnt = scc_core(p, core, inCore, comp);\n    }\n\n    // ----- Exact simulation SA on real objective -----\n    array<int, N> curCnt{}, bestCnt{}, tmpCnt{};\n    Plan curP = p, bestP = p;\n    int curE = simulate_plan(curP, L, T, curCnt);\n    int bestE = curE;\n    bestCnt = curCnt;\n\n    auto pick_x = [&]() -> int {\n        // choose among core (if 0 not in core, it is only visited once; no need to optimize edges by counts)\n        if (core.size() == 1) return core[0];\n        // rejection sampling biased by visit counts\n        int maxC = 1;\n        for (int v : core) maxC = max(maxC, curCnt[v]);\n        while (true) {\n            int v = core[rng.nextInt((int)core.size())];\n            if (rng.nextInt(maxC) < curCnt[v]) return v;\n        }\n    };\n\n    auto pick_dest_deficit = [&]() -> int {\n        // pick a destination in core biased to under-visited nodes\n        int maxD = 1;\n        for (int v : core) maxD = max(maxD, max(0, T[v] - curCnt[v]));\n        for (int tries = 0; tries < 50; ++tries) {\n            int v = core[rng.nextInt((int)core.size())];\n            int d = max(0, T[v] - curCnt[v]);\n            if (rng.nextInt(maxD) < d + 1) return v;\n        }\n        return core[rng.nextInt((int)core.size())];\n    };\n\n    auto core_strong_connected = [&](const Plan& pp) -> bool {\n        if (core.size() <= 1) return true;\n        // BFS from some start in core\n        int s = core[0];\n        vector<char> vis(N, 0);\n        deque<int> dq;\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            int to1 = pp.a[v], to2 = pp.b[v];\n            if (inCore[to1] && !vis[to1]) { vis[to1] = 1; dq.push_back(to1); }\n            if (inCore[to2] && !vis[to2]) { vis[to2] = 1; dq.push_back(to2); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n\n        // reverse BFS\n        vector<vector<int>> rg(N);\n        for (int v : core) {\n            rg[pp.a[v]].push_back(v);\n            rg[pp.b[v]].push_back(v);\n        }\n        fill(vis.begin(), vis.end(), 0);\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (int u : rg[v]) if (inCore[u] && !vis[u]) { vis[u] = 1; dq.push_back(u); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n        return true;\n    };\n\n    const double DYN_START = elapsedSec();\n    while (elapsedSec() < TIME_LIMIT) {\n        double t = (elapsedSec() - DYN_START) / max(1e-9, (TIME_LIMIT - DYN_START));\n        t = min(1.0, max(0.0, t));\n        double temp = 6000.0 * pow(30.0 / 6000.0, t);\n\n        int type = rng.nextInt(100);\n        int x1=-1, e1=0, old1=-1;\n        int x2=-1, e2=0, old2=-1;\n        int olda=-1, oldb=-1;\n\n        if (type < 72) {\n            // change one edge\n            x1 = pick_x();\n            e1 = rng.nextInt(2);\n            int& edge = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            old1 = edge;\n            int y = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y == old1) continue;\n            edge = y;\n        } else if (type < 92) {\n            // swap two edges\n            x1 = pick_x(); e1 = rng.nextInt(2);\n            x2 = pick_x(); e2 = rng.nextInt(2);\n            int& ed1 = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            int& ed2 = (e2==0 ? curP.a[x2] : curP.b[x2]);\n            old1 = ed1; old2 = ed2;\n            if (old1 == old2) continue;\n            ed1 = old2; ed2 = old1;\n        } else {\n            // reset both edges of one node\n            x1 = pick_x();\n            olda = curP.a[x1];\n            oldb = curP.b[x1];\n            int y1 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            int y2 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y1 == olda && y2 == oldb) continue;\n            curP.a[x1] = y1;\n            curP.b[x1] = y2;\n        }\n\n        // Keep core closed (should already hold by how we pick destinations), and keep core strongly connected\n        if (!core_strong_connected(curP)) {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n            continue;\n        }\n\n        int newE = simulate_plan(curP, L, T, tmpCnt);\n        int delta = newE - curE;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)delta / temp)) accept = true;\n\n        if (accept) {\n            curE = newE;\n            curCnt = tmpCnt;\n            if (curE < bestE) {\n                bestE = curE;\n                bestP = curP;\n                bestCnt = curCnt;\n            }\n        } else {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n        }\n    }\n\n    // Output best plan found\n    for (int i = 0; i < N; ++i) {\n        cout << bestP.a[i] << ' ' << bestP.b[i] << \"\\n\";\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\nusing namespace std;\n\nstruct City {\n    int lx, rx, ly, ry;\n    int cx, cy;\n    uint32_t morton;\n};\n\nstatic inline uint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nstatic inline uint32_t morton2D(uint32_t x, uint32_t y) {\n    return part1by1(x) | (part1by1(y) << 1);\n}\n\nstruct EdgeW {\n    int a, b;\n    uint16_t w;\n};\n\nstruct CandEdge {\n    int a, b;\n    uint16_t lb;\n    uint16_t cd;\n    uint8_t tp; // 0=query,1=neighbor,2=fallback\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    int ms() const {\n        return (int)chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<City> cities;\n    vector<uint16_t> distMat; // center-based floor euclid; N*N\n\n    int q_used = 0;\n    Timer timer;\n\n    vector<vector<int>> groups;\n    vector<vector<pair<int,int>>> queryEdges;\n    vector<char> fullQueried;\n\n    vector<vector<pair<int,int>>> fallbackEdges;\n    vector<vector<EdgeW>> fallbackEdgesW;\n    vector<long long> groupEstCost;\n\n    uint16_t dist_est(int a, int b) const { return distMat[a * N + b]; }\n\n    uint16_t rect_mindist(int a, int b) const {\n        const auto &A = cities[a];\n        const auto &B = cities[b];\n        long long dx = 0, dy = 0;\n        if (A.rx < B.lx) dx = (long long)B.lx - A.rx;\n        else if (B.rx < A.lx) dx = (long long)A.lx - B.rx;\n        if (A.ry < B.ly) dy = (long long)B.ly - A.ry;\n        else if (B.ry < A.ly) dy = (long long)A.ly - B.ry;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)floor(sqrt((double)sq));\n        if (d < 0) d = 0;\n        if (d > 65535) d = 65535;\n        return (uint16_t)d;\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int v : subset) cout << \" \" << v;\n        cout << \"\\n\" << flush;\n\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, l - 1));\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            cin >> a >> b;\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        q_used++;\n        return edges;\n    }\n\n    long long prim_build(const vector<int>& nodes, vector<pair<int,int>>* outEdges, vector<EdgeW>* outEdgesW) {\n        int s = (int)nodes.size();\n        if (outEdges) outEdges->clear();\n        if (outEdgesW) outEdgesW->clear();\n        if (s <= 1) return 0;\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        vector<uint16_t> minc(s, INF);\n        vector<int> parent(s, -1);\n        vector<char> used(s, false);\n        minc[0] = 0;\n\n        long long sum = 0;\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) if (!used[i]) {\n                if (v == -1 || minc[i] < minc[v]) v = i;\n            }\n            used[v] = true;\n            if (parent[v] != -1) {\n                int a = nodes[v], b = nodes[parent[v]];\n                uint16_t w = dist_est(a, b);\n                sum += (int)w;\n                if (a > b) swap(a, b);\n                if (outEdges) outEdges->push_back({a, b});\n                if (outEdgesW) outEdgesW->push_back({a, b, w});\n            }\n            int va = nodes[v];\n            for (int u = 0; u < s; u++) if (!used[u]) {\n                uint16_t d = dist_est(va, nodes[u]);\n                if (d < minc[u]) {\n                    minc[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n        return sum;\n    }\n\n    long long eval_groups(const vector<vector<int>>& gr) {\n        long long total = 0;\n        for (int k = 0; k < M; k++) total += prim_build(gr[k], nullptr, nullptr);\n        return total;\n    }\n\n    vector<vector<int>> build_groups_sweep(const vector<int>& order, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        int idx = 0;\n        for (int t = 0; t < M; t++) {\n            int k = groupOrder[t];\n            gr[k].reserve(G[k]);\n            for (int i = 0; i < G[k]; i++) gr[k].push_back(order[idx++]);\n        }\n        return gr;\n    }\n\n    vector<vector<int>> build_groups_grow(const vector<int>& seedOrder, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        vector<char> used(N, false);\n        vector<uint16_t> best(N);\n\n        int ptr = 0;\n        auto next_seed = [&]() -> int {\n            while (ptr < N && used[seedOrder[ptr]]) ptr++;\n            if (ptr >= N) {\n                for (int i = 0; i < N; i++) if (!used[i]) return i;\n                return -1;\n            }\n            return seedOrder[ptr];\n        };\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n\n        for (int gid : groupOrder) {\n            int need = G[gid];\n            gr[gid].clear();\n            gr[gid].reserve(need);\n\n            int seed = next_seed();\n            if (seed < 0) break;\n            used[seed] = true;\n            gr[gid].push_back(seed);\n\n            for (int v = 0; v < N; v++) best[v] = used[v] ? INF : dist_est(seed, v);\n\n            for (int t = 1; t < need; t++) {\n                int pick = -1;\n                uint16_t bd = INF;\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = best[v];\n                    if (pick == -1 || d < bd) { bd = d; pick = v; }\n                }\n                if (pick < 0) break;\n                used[pick] = true;\n                gr[gid].push_back(pick);\n\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = dist_est(pick, v);\n                    if (d < best[v]) best[v] = d;\n                }\n            }\n        }\n        return gr;\n    }\n\n    // subset for edge (u,v): include u,v and nearest around each\n    vector<int> make_edge_subset(int k, int u, int v) {\n        const auto &nodes = groups[k];\n        int s = (int)nodes.size();\n        int want = min(L, s);\n        if (want < 3) return {u, v};\n\n        int rem = want - 2;\n        int a_take = rem / 2;\n        int b_take = rem - a_take;\n\n        vector<pair<uint16_t,int>> cu, cv;\n        cu.reserve(s);\n        cv.reserve(s);\n        for (int x : nodes) {\n            if (x == u || x == v) continue;\n            cu.emplace_back(dist_est(u, x), x);\n            cv.emplace_back(dist_est(v, x), x);\n        }\n\n        auto take_best = [&](vector<pair<uint16_t,int>>& c, int take) {\n            if (take <= 0) { c.clear(); return; }\n            if ((int)c.size() > take) {\n                nth_element(c.begin(), c.begin() + take, c.end());\n                c.resize(take);\n            }\n            sort(c.begin(), c.end());\n        };\n        take_best(cu, a_take);\n        take_best(cv, b_take);\n\n        vector<int> subset;\n        subset.reserve(want);\n        subset.push_back(u);\n        subset.push_back(v);\n        auto push_unique = [&](int x) {\n            for (int y : subset) if (y == x) return;\n            subset.push_back(x);\n        };\n        for (auto &p : cu) push_unique(p.second);\n        for (auto &p : cv) push_unique(p.second);\n\n        if ((int)subset.size() < want) {\n            vector<pair<uint16_t,int>> fill;\n            fill.reserve(s);\n            for (int x : nodes) {\n                bool ok = true;\n                for (int y : subset) if (y == x) { ok = false; break; }\n                if (!ok) continue;\n                uint16_t d = min(dist_est(u, x), dist_est(v, x));\n                fill.emplace_back(d, x);\n            }\n            int need = want - (int)subset.size();\n            if ((int)fill.size() > need) {\n                nth_element(fill.begin(), fill.begin() + need, fill.end());\n                fill.resize(need);\n            }\n            sort(fill.begin(), fill.end());\n            for (auto &p : fill) subset.push_back(p.second);\n        }\n        if ((int)subset.size() > want) subset.resize(want);\n        return subset;\n    }\n\n    static uint64_t subset_hash(vector<int> sub) {\n        sort(sub.begin(), sub.end());\n        uint64_t x = 1469598103934665603ULL;\n        for (int v : sub) {\n            x ^= (uint64_t)(v + 1);\n            x *= 1099511628211ULL;\n        }\n        return x;\n    }\n\n    // Sparse neighbor edges: connect each node to next K in several sorted orders (O(s log s))\n    vector<pair<int,int>> build_neighbor_edges(const vector<int>& nodes, int Kwin) {\n        int s = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (s <= 1) return edges;\n        edges.reserve((size_t)s * Kwin * 3);\n\n        auto add_window = [&](vector<int>& ord) {\n            for (int i = 0; i < s; i++) {\n                int u = ord[i];\n                for (int d = 1; d <= Kwin && i + d < s; d++) {\n                    int v = ord[i + d];\n                    int a = u, b = v;\n                    if (a > b) swap(a, b);\n                    edges.emplace_back(a, b);\n                }\n            }\n        };\n\n        vector<int> ordx = nodes, ordy = nodes, ordm = nodes;\n        sort(ordx.begin(), ordx.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ordy.begin(), ordy.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ordm.begin(), ordm.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n\n        add_window(ordx);\n        add_window(ordy);\n        add_window(ordm);\n\n        sort(edges.begin(), edges.end());\n        edges.erase(unique(edges.begin(), edges.end()), edges.end());\n        return edges;\n    }\n\n    vector<pair<int,int>> build_final_tree(int k) {\n        const vector<int>& nodes = groups[k];\n        int s = (int)nodes.size();\n        if (s <= 1) return {};\n        if (s == 2) {\n            int a = nodes[0], b = nodes[1];\n            if (a > b) swap(a,b);\n            return {{a,b}};\n        }\n\n        if (fullQueried[k]) {\n            auto res = queryEdges[k];\n            if ((int)res.size() == s - 1) return res;\n        }\n\n        // local index mapping\n        vector<int> pos(N, -1);\n        for (int i = 0; i < s; i++) pos[nodes[i]] = i;\n\n        auto norm_dedup = [&](vector<pair<int,int>>& es) {\n            for (auto &e : es) if (e.first > e.second) swap(e.first, e.second);\n            sort(es.begin(), es.end());\n            es.erase(unique(es.begin(), es.end()), es.end());\n        };\n\n        vector<pair<int,int>> qE = queryEdges[k];\n        vector<pair<int,int>> fb = fallbackEdges[k];\n        norm_dedup(qE);\n        norm_dedup(fb);\n\n        vector<pair<int,int>> nb = build_neighbor_edges(nodes, 4);\n        norm_dedup(nb);\n\n        vector<CandEdge> cand;\n        cand.reserve(qE.size() + nb.size() + fb.size());\n\n        auto add_list = [&](const vector<pair<int,int>>& es, uint8_t tp) {\n            for (auto &e : es) {\n                int a = e.first, b = e.second;\n                if (pos[a] < 0 || pos[b] < 0) continue;\n                uint16_t lb = rect_mindist(a, b);\n                uint16_t cd = dist_est(a, b);\n                cand.push_back({a, b, lb, cd, tp});\n            }\n        };\n        add_list(qE, 0);\n        add_list(nb, 1);\n        add_list(fb, 2);\n\n        sort(cand.begin(), cand.end(), [&](const CandEdge& A, const CandEdge& B){\n            if (A.tp != B.tp) return A.tp < B.tp;\n            if (A.lb != B.lb) return A.lb < B.lb;\n            if (A.cd != B.cd) return A.cd < B.cd;\n            if (A.a != B.a) return A.a < B.a;\n            return A.b < B.b;\n        });\n\n        atcoder::dsu dsu(s);\n        vector<pair<int,int>> res;\n        res.reserve(s - 1);\n\n        for (auto &e : cand) {\n            int pa = pos[e.a], pb = pos[e.b];\n            if (pa < 0 || pb < 0) continue;\n            if (dsu.same(pa, pb)) continue;\n            dsu.merge(pa, pb);\n            int a = e.a, b = e.b;\n            if (a > b) swap(a, b);\n            res.emplace_back(a, b);\n            if ((int)res.size() == s - 1) break;\n        }\n\n        if ((int)res.size() != s - 1) {\n            // ultimate fallback: estimated MST edges must be valid\n            res = fb;\n            if ((int)res.size() != s - 1) {\n                res.clear();\n                for (int i = 1; i < s; i++) {\n                    int a = nodes[i-1], b = nodes[i];\n                    if (a > b) swap(a, b);\n                    res.emplace_back(a, b);\n                }\n            }\n        }\n        return res;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        cities.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto &c = cities[i];\n            cin >> c.lx >> c.rx >> c.ly >> c.ry;\n            c.cx = (c.lx + c.rx) / 2;\n            c.cy = (c.ly + c.ry) / 2;\n            uint32_t x = (uint32_t)min(16383, max(0, c.cx));\n            uint32_t y = (uint32_t)min(16383, max(0, c.cy));\n            c.morton = morton2D(x, y);\n        }\n\n        // precompute center distances\n        distMat.assign((size_t)N * N, 0);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                long long dx = cities[i].cx - cities[j].cx;\n                long long dy = cities[i].cy - cities[j].cy;\n                long long sq = dx * dx + dy * dy;\n                int d = (int)floor(sqrt((double)sq));\n                if (d < 0) d = 0;\n                if (d > 65535) d = 65535;\n                distMat[i * N + j] = (uint16_t)d;\n                distMat[j * N + i] = (uint16_t)d;\n            }\n        }\n\n        // orderings\n        vector<int> ord_m(N), ord_x(N), ord_y(N), ord_xy1(N), ord_xy2(N);\n        iota(ord_m.begin(), ord_m.end(), 0);\n        iota(ord_x.begin(), ord_x.end(), 0);\n        iota(ord_y.begin(), ord_y.end(), 0);\n        iota(ord_xy1.begin(), ord_xy1.end(), 0);\n        iota(ord_xy2.begin(), ord_xy2.end(), 0);\n\n        sort(ord_m.begin(), ord_m.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_x.begin(), ord_x.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_y.begin(), ord_y.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ord_xy1.begin(), ord_xy1.end(), [&](int a, int b){\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            return a < b;\n        });\n        sort(ord_xy2.begin(), ord_xy2.end(), [&](int a, int b){\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n\n        vector<int> go_given(M), go_desc(M);\n        iota(go_given.begin(), go_given.end(), 0);\n        iota(go_desc.begin(), go_desc.end(), 0);\n        sort(go_desc.begin(), go_desc.end(), [&](int a, int b){\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        // deterministic rng\n        uint64_t h = 1469598103934665603ULL;\n        for (int i = 0; i < N; i++) {\n            h ^= (uint64_t)cities[i].cx + 10007ULL * (uint64_t)cities[i].cy;\n            h *= 1099511628211ULL;\n        }\n        mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n        // candidates (reduced count to keep runtime low)\n        vector<vector<vector<int>>> candidates;\n        candidates.reserve(12);\n        candidates.push_back(build_groups_sweep(ord_m, go_desc));\n        candidates.push_back(build_groups_sweep(ord_m, go_given));\n        candidates.push_back(build_groups_sweep(ord_x, go_given));\n        candidates.push_back(build_groups_sweep(ord_y, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy1, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy2, go_given));\n        candidates.push_back(build_groups_grow(ord_m, go_desc));\n        candidates.push_back(build_groups_grow(ord_m, go_given));\n        candidates.push_back(build_groups_grow(ord_x, go_desc));\n        candidates.push_back(build_groups_grow(ord_y, go_desc));\n        for (int t = 0; t < 2; t++) {\n            vector<int> go = go_desc;\n            shuffle(go.begin(), go.end(), rng);\n            candidates.push_back(build_groups_grow(ord_m, go));\n        }\n\n        long long bestScore = (1LL<<62);\n        int bestIdx = 0;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            long long sc = eval_groups(candidates[i]);\n            if (sc < bestScore) { bestScore = sc; bestIdx = i; }\n        }\n        groups = move(candidates[bestIdx]);\n\n        // fallback MST per group\n        fallbackEdges.assign(M, {});\n        fallbackEdgesW.assign(M, {});\n        groupEstCost.assign(M, 0);\n        for (int k = 0; k < M; k++) {\n            groupEstCost[k] = prim_build(groups[k], &fallbackEdges[k], &fallbackEdgesW[k]);\n        }\n\n        // --- Query planning with time guard ---\n        queryEdges.assign(M, {});\n        fullQueried.assign(M, false);\n        q_used = 0;\n\n        int num_large = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) num_large++;\n\n        int reserve_for_large = 0;\n        if (num_large > 0) {\n            reserve_for_large = min(Q, max(60, min(Q * 2 / 3, num_large * 10)));\n        }\n        int small_query_limit = max(0, Q - reserve_for_large);\n\n        vector<int> small;\n        for (int k = 0; k < M; k++) {\n            int s = (int)groups[k].size();\n            if (s >= 3 && s <= L) small.push_back(k);\n        }\n        sort(small.begin(), small.end(), [&](int a, int b){\n            int sa = (int)groups[a].size(), sb = (int)groups[b].size();\n            if (sa != sb) return sa > sb;\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return a < b;\n        });\n\n        auto time_ok = [&](){\n            // Keep margin for output construction; interactive overhead can be nontrivial.\n            return timer.ms() <= 1650;\n        };\n\n        for (int k : small) {\n            if (!time_ok()) break;\n            if (q_used >= small_query_limit) break;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        vector<int> large;\n        long long totalLargeCost = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) {\n            large.push_back(k);\n            totalLargeCost += groupEstCost[k];\n        }\n        sort(large.begin(), large.end(), [&](int a, int b){\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return (int)groups[a].size() > (int)groups[b].size();\n        });\n\n        unordered_set<uint64_t> usedSub;\n        usedSub.reserve(512);\n\n        for (int k : large) {\n            if (!time_ok()) break;\n            if (q_used >= Q) break;\n            int remQ = Q - q_used;\n            if (remQ <= 0) break;\n\n            int myBudget = 10;\n            if (totalLargeCost > 0) {\n                myBudget = (int)llround((double)reserve_for_large * (double)groupEstCost[k] / (double)totalLargeCost);\n            }\n            myBudget = max(4, min(myBudget, 16));\n            myBudget = min(myBudget, remQ);\n\n            auto edgesW = fallbackEdgesW[k];\n            sort(edgesW.begin(), edgesW.end(), [&](const EdgeW& A, const EdgeW& B){ return A.w > B.w; });\n\n            int qi = 0;\n            int takeEdges = min((int)edgesW.size(), myBudget * 3);\n            for (int i = 0; i < takeEdges && qi < myBudget && q_used < Q; i++) {\n                if (!time_ok()) break;\n                int u = edgesW[i].a, v = edgesW[i].b;\n                auto subset = make_edge_subset(k, u, v);\n                if ((int)subset.size() < 3) continue;\n                uint64_t hh = subset_hash(subset);\n                if (usedSub.count(hh)) continue;\n                usedSub.insert(hh);\n\n                auto e = do_query(subset);\n                queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                qi++;\n            }\n        }\n\n        // Any remaining queries -> unqueried small groups (only if time allows)\n        for (int k : small) {\n            if (!time_ok()) break;\n            if (q_used >= Q) break;\n            if (fullQueried[k]) continue;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        // --- Output ---\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            auto edges = build_final_tree(k);\n            int need = (int)groups[k].size() - 1;\n            if ((int)edges.size() != need) edges = fallbackEdges[k];\n\n            for (auto &e : edges) {\n                int a = e.first, b = e.second;\n                if (a > b) swap(a, b);\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout << flush;\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action {\n    char a, d;\n};\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dirc[4] = {'U', 'D', 'L', 'R'};\nstatic const char actc[3] = {'M', 'S', 'A'};\n\nstruct Solver {\n    int N, M;\n    vector<pair<int,int>> P; // P[0]=start, P[1..M-1]=targets\n\n    // order in visit sequence, -1 if not a target/start\n    int ord[20][20];\n\n    // global blocks\n    uint8_t blockg[20][20]{};\n    int totalBlocks = 0;\n\n    vector<Action> answer;\n\n    // ---- parameters ----\n    static constexpr int KMAX = 13;                 // candidate toggle bits\n    static constexpr int MAX_BLOCKS = 120;          // soft safety cap\n    static constexpr int EXTRA_LOOKAHEAD = 2;       // allow +2 to invest\n\n    // Buffers for local BFS (max size for KMAX)\n    static constexpr int NN = 400;\n    static constexpr int MAX_STATES = NN * (1 << KMAX);\n\n    vector<int16_t> distBuf;       // -1 = unvisited\n    vector<int32_t> prevBuf;\n    vector<uint8_t> prevOpBuf;\n    vector<int> visitedStates;\n    vector<int> q;\n\n    Solver() {\n        distBuf.assign(MAX_STATES, -1);\n        prevBuf.resize(MAX_STATES);\n        prevOpBuf.resize(MAX_STATES);\n        visitedStates.reserve(1 << 20);\n        q.reserve(1 << 20);\n    }\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n    inline int posId(int x, int y) const { return x * N + y; }\n    inline pair<int,int> idPos(int id) const { return {id / N, id % N}; }\n\n    inline bool forbiddenCell(int x, int y, int curIndex) const {\n        // Forbid placing blocks on current or future targets (ord > curIndex).\n        // Past targets (ord <= curIndex) are allowed and useful as stoppers.\n        int t = ord[x][y];\n        return (t != -1 && t > curIndex);\n    }\n\n    // ---- Fixed-block BFS helpers (Move+Slide) ----\n    inline int slideStop(const uint8_t b[20][20], int x, int y, int dir) const {\n        int nx = x, ny = y;\n        while (true) {\n            int tx = nx + di[dir], ty = ny + dj[dir];\n            if (!inside(tx, ty)) break;\n            if (b[tx][ty]) break;\n            nx = tx; ny = ty;\n        }\n        return posId(nx, ny);\n    }\n\n    int shortestFixedLen(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S = posId(s.first, s.second);\n        int G = posId(g.first, g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> qq;\n        int head = 0, tail = 0;\n\n        dist[S] = 0;\n        qq[tail++] = S;\n\n        while (head < tail) {\n            int v = qq[head++];\n            if (v == G) return dist[v];\n            auto [x, y] = idPos(v);\n\n            for (int d = 0; d < 4; d++) {\n                // Move\n                int mx = x + di[d], my = y + dj[d];\n                if (inside(mx, my) && !b[mx][my]) {\n                    int to = posId(mx, my);\n                    if (dist[to] == -1) {\n                        dist[to] = dist[v] + 1;\n                        qq[tail++] = to;\n                    }\n                }\n                // Slide\n                int to = slideStop(b, x, y, d);\n                if (to != v && dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    qq[tail++] = to;\n                }\n            }\n        }\n        return 1e9; // unreachable (should be rare)\n    }\n\n    vector<Action> shortestFixedPath(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S = posId(s.first, s.second);\n        int G = posId(g.first, g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> prev;\n        prev.fill(-1);\n        array<uint8_t, NN> prevOp;\n        prevOp.fill(255);\n\n        array<int, NN> qq;\n        int head = 0, tail = 0;\n\n        dist[S] = 0;\n        qq[tail++] = S;\n\n        while (head < tail) {\n            int v = qq[head++];\n            if (v == G) break;\n            auto [x, y] = idPos(v);\n\n            for (int d = 0; d < 4; d++) {\n                // Move\n                int mx = x + di[d], my = y + dj[d];\n                if (inside(mx, my) && !b[mx][my]) {\n                    int to = posId(mx, my);\n                    if (dist[to] == -1) {\n                        dist[to] = dist[v] + 1;\n                        prev[to] = v;\n                        prevOp[to] = (0 * 4 + d);\n                        qq[tail++] = to;\n                    }\n                }\n                // Slide\n                int to = slideStop(b, x, y, d);\n                if (to != v && dist[to] == -1) {\n                    dist[to] = dist[v] + 1;\n                    prev[to] = v;\n                    prevOp[to] = (1 * 4 + d);\n                    qq[tail++] = to;\n                }\n            }\n        }\n\n        if (dist[G] == -1) return {};\n\n        vector<Action> res;\n        int cur = G;\n        while (cur != S) {\n            uint8_t code = prevOp[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prev[cur];\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    // ---- Local toggle BFS with lookahead selection ----\n    vector<Action> planLocalWithLookahead(\n        int curIndex, pair<int,int> s, pair<int,int> g,\n        int baselineLen, bool hasNext, pair<int,int> nxt,\n        int baselineObj, int &bestObjOut\n    ) {\n        bestObjOut = baselineObj;\n\n        // Small baselines: don't spend time.\n        if (baselineLen <= 1) return {};\n\n        // Candidate priorities\n        int pr[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) pr[i][j] = -1;\n\n        auto addCand = [&](int x, int y, int p) {\n            if (!inside(x, y)) return;\n            if (forbiddenCell(x, y, curIndex)) return; // forbid current/future targets\n            pr[x][y] = max(pr[x][y], p);\n        };\n\n        int sx = s.first, sy = s.second;\n        int gx = g.first, gy = g.second;\n\n        // Around goal (strong)\n        for (int d = 0; d < 4; d++) {\n            addCand(gx + di[d], gy + dj[d], 220);          // immediate stopper cells\n            addCand(gx + 2*di[d], gy + 2*dj[d], 160);      // slightly farther\n        }\n        for (int dx = -3; dx <= 3; dx++) for (int dy = -3; dy <= 3; dy++) {\n            if (abs(dx) + abs(dy) <= 3) addCand(gx + dx, gy + dy, 130);\n        }\n\n        // Around start\n        for (int d = 0; d < 4; d++) addCand(sx + di[d], sy + dj[d], 140);\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            if (abs(dx) + abs(dy) <= 2) addCand(sx + dx, sy + dy, 90);\n        }\n\n        // L-shape corners (good turning points)\n        int c1x = sx, c1y = gy;\n        int c2x = gx, c2y = sy;\n        for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {\n            addCand(c1x + dx, c1y + dy, 120);\n            addCand(c2x + dx, c2y + dy, 120);\n        }\n\n        // Same row/col near goal (potential stoppers)\n        for (int t = 1; t <= 3; t++) {\n            addCand(gx, gy + t, 80);\n            addCand(gx, gy - t, 80);\n            addCand(gx + t, gy, 80);\n            addCand(gx - t, gy, 80);\n        }\n\n        // Existing blocks near start/goal (allow removing)\n        for (int dx = -3; dx <= 3; dx++) for (int dy = -3; dy <= 3; dy++) {\n            int x = gx + dx, y = gy + dy;\n            if (inside(x,y) && blockg[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x, y, 125);\n        }\n        for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n            int x = sx + dx, y = sy + dy;\n            if (inside(x,y) && blockg[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x, y, 95);\n        }\n\n        // If we have a next target, prep around it slightly (investment)\n        if (hasNext) {\n            int nx = nxt.first, ny = nxt.second;\n            for (int d = 0; d < 4; d++) addCand(nx + di[d], ny + dj[d], 70);\n            for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) {\n                if (abs(dx) + abs(dy) <= 2) addCand(nx + dx, ny + dy, 45);\n            }\n        }\n\n        struct C { int p,x,y; };\n        vector<C> cand;\n        cand.reserve(200);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (pr[i][j] >= 0) cand.push_back({pr[i][j], i, j});\n        }\n        if (cand.empty()) return {};\n\n        sort(cand.begin(), cand.end(), [&](const C& a, const C& b){\n            if (a.p != b.p) return a.p > b.p;\n            // tie-break: closer to (start+goal)/2 a bit\n            int mx = (sx + gx) / 2, my = (sy + gy) / 2;\n            int da = abs(a.x - mx) + abs(a.y - my);\n            int db = abs(b.x - mx) + abs(b.y - my);\n            if (da != db) return da < db;\n            if (a.x != b.x) return a.x < b.x;\n            return a.y < b.y;\n        });\n\n        int K = min((int)cand.size(), KMAX);\n        cand.resize(K);\n        int MSZ = 1 << K;\n\n        int idx[20][20];\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) idx[i][j] = -1;\n        for (int t = 0; t < K; t++) idx[cand[t].x][cand[t].y] = t;\n\n        // init mask\n        int initMask = 0;\n        for (int t = 0; t < K; t++) {\n            if (blockg[cand[t].x][cand[t].y]) initMask |= (1 << t);\n        }\n        int baseBlocks = totalBlocks - __builtin_popcount((unsigned)initMask);\n\n        auto sid = [&](int mask, int pos) { return mask * NN + pos; };\n\n        auto isBlocked = [&](int x, int y, int mask) -> bool {\n            if (!inside(x, y)) return true;\n            int t = idx[x][y];\n            if (t >= 0) return (mask >> t) & 1;\n            return blockg[x][y];\n        };\n\n        auto slideStopMask = [&](int x, int y, int dir, int mask) -> int {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[dir], ty = ny + dj[dir];\n                if (!inside(tx, ty)) break;\n                if (isBlocked(tx, ty, mask)) break;\n                nx = tx; ny = ty;\n            }\n            return posId(nx, ny);\n        };\n\n        int Spos = posId(s.first, s.second);\n        int Gpos = posId(g.first, g.second);\n\n        int limit = baselineLen + (hasNext ? EXTRA_LOOKAHEAD : 0);\n\n        // BFS init\n        visitedStates.clear();\n        q.clear();\n\n        auto pushState = [&](int id, int16_t d, int32_t parent, uint8_t op) {\n            distBuf[id] = d;\n            prevBuf[id] = parent;\n            prevOpBuf[id] = op;\n            visitedStates.push_back(id);\n            q.push_back(id);\n        };\n\n        int s0 = sid(initMask, Spos);\n        pushState(s0, 0, -1, 255);\n\n        // BFS\n        size_t head = 0;\n        while (head < q.size()) {\n            int v = q[head++];\n            int16_t dcur = distBuf[v];\n            if (dcur >= limit) continue;\n\n            int mask = v / NN;\n            int pos  = v % NN;\n            auto [x, y] = idPos(pos);\n\n            // Move/Slide\n            for (int dd = 0; dd < 4; dd++) {\n                // Move\n                int mx = x + di[dd], my = y + dj[dd];\n                if (inside(mx, my) && !isBlocked(mx, my, mask)) {\n                    int to = sid(mask, posId(mx, my));\n                    if (distBuf[to] == -1) pushState(to, dcur + 1, v, (0 * 4 + dd));\n                }\n                // Slide\n                int spos = slideStopMask(x, y, dd, mask);\n                if (spos != pos) {\n                    int to = sid(mask, spos);\n                    if (distBuf[to] == -1) pushState(to, dcur + 1, v, (1 * 4 + dd));\n                }\n            }\n\n            // Alter adjacent candidate only\n            for (int dd = 0; dd < 4; dd++) {\n                int ax = x + di[dd], ay = y + dj[dd];\n                if (!inside(ax, ay)) continue;\n                int t = idx[ax][ay];\n                if (t < 0) continue;\n                if (forbiddenCell(ax, ay, curIndex)) continue; // safety\n\n                int nmask = mask ^ (1 << t);\n                if (baseBlocks + __builtin_popcount((unsigned)nmask) > MAX_BLOCKS) continue;\n\n                int to = sid(nmask, pos);\n                if (distBuf[to] == -1) pushState(to, dcur + 1, v, (2 * 4 + dd));\n            }\n        }\n\n        // Collect reachable goal states within limit\n        struct GS { int id; int16_t d; };\n        vector<GS> goals;\n        goals.reserve(MSZ);\n\n        for (int mask = 0; mask < MSZ; mask++) {\n            int id = sid(mask, Gpos);\n            int16_t d = distBuf[id];\n            if (d != -1 && d <= limit) goals.push_back({id, d});\n        }\n        if (goals.empty()) {\n            for (int id : visitedStates) distBuf[id] = -1;\n            return {};\n        }\n\n        sort(goals.begin(), goals.end(), [](const GS& a, const GS& b){\n            if (a.d != b.d) return a.d < b.d;\n            return a.id < b.id;\n        });\n        if ((int)goals.size() > 32) goals.resize(32);\n\n        // Evaluate with lookahead\n        int bestState = goals[0].id;\n        int bestObj = 1e9;\n        int bestD1 = 1e9;\n        int bestPop = 1e9;\n\n        uint8_t temp[20][20];\n\n        for (auto &gs : goals) {\n            int id = gs.id;\n            int16_t d1 = gs.d;\n            int mask = id / NN;\n\n            // build temp blocks\n            for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) temp[i][j] = blockg[i][j];\n            for (int t = 0; t < K; t++) {\n                temp[cand[t].x][cand[t].y] = (mask >> t) & 1;\n            }\n\n            int d2 = 0;\n            if (hasNext) d2 = shortestFixedLen(temp, g, nxt);\n\n            int obj = (int)d1 + d2;\n            int pop = __builtin_popcount((unsigned)mask);\n\n            if (obj < bestObj ||\n                (obj == bestObj && d1 < bestD1) ||\n                (obj == bestObj && d1 == bestD1 && pop < bestPop)) {\n                bestObj = obj;\n                bestD1 = d1;\n                bestPop = pop;\n                bestState = id;\n            }\n        }\n\n        bestObjOut = bestObj;\n\n        // Reconstruct bestState path\n        vector<Action> res;\n        int cur = bestState;\n        while (cur != s0) {\n            uint8_t code = prevOpBuf[cur];\n            int a = code / 4;\n            int d = code % 4;\n            res.push_back(Action{actc[a], dirc[d]});\n            cur = prevBuf[cur];\n            if (cur < 0) break; // safety\n        }\n        reverse(res.begin(), res.end());\n\n        // reset dist buffer\n        for (int id : visitedStates) distBuf[id] = -1;\n\n        return res;\n    }\n\n    // ---- Apply action to global state ----\n    void applyAction(pair<int,int>& cur, const Action& ac) {\n        int d = 0;\n        while (d < 4 && dirc[d] != ac.d) d++;\n        int x = cur.first, y = cur.second;\n\n        if (ac.a == 'M') {\n            cur = {x + di[d], y + dj[d]};\n        } else if (ac.a == 'S') {\n            int nx = x, ny = y;\n            while (true) {\n                int tx = nx + di[d], ty = ny + dj[d];\n                if (!inside(tx, ty)) break;\n                if (blockg[tx][ty]) break;\n                nx = tx; ny = ty;\n            }\n            cur = {nx, ny};\n        } else { // 'A'\n            int ax = x + di[d], ay = y + dj[d];\n            bool before = blockg[ax][ay];\n            blockg[ax][ay] = !blockg[ax][ay];\n            if (!before && blockg[ax][ay]) totalBlocks++;\n            if (before && !blockg[ax][ay]) totalBlocks--;\n        }\n    }\n\n    void solve() {\n        pair<int,int> cur = P[0];\n\n        for (int k = 0; k < M - 1; k++) {\n            pair<int,int> goal = P[k + 1];\n            bool hasNext = (k + 2 < M);\n            pair<int,int> nxt = hasNext ? P[k + 2] : make_pair(-1, -1);\n\n            // Baseline shortest with current blocks (Move+Slide)\n            vector<Action> base = shortestFixedPath(blockg, cur, goal);\n            if (base.empty()) {\n                // extremely rare; as a fallback, do nothing (will likely fail gracefully)\n                // but public tests should not hit this\n                base.clear();\n            }\n            int baseLen = (int)base.size();\n            int baseNextLen = hasNext ? shortestFixedLen(blockg, goal, nxt) : 0;\n            int baseObj = baseLen + baseNextLen;\n\n            // Local plan with toggles and lookahead selection\n            int localObj = baseObj;\n            vector<Action> local = planLocalWithLookahead(\n                k, cur, goal, baseLen, hasNext, nxt, baseObj, localObj\n            );\n\n            bool useLocal = false;\n            if (!local.empty()) {\n                if (localObj < baseObj) useLocal = true;\n                else if (localObj == baseObj && (int)local.size() < baseLen) useLocal = true;\n            }\n\n            const vector<Action>& use = useLocal ? local : base;\n\n            for (auto &ac : use) {\n                if ((int)answer.size() >= 2 * N * M) break;\n                answer.push_back(ac);\n                applyAction(cur, ac);\n            }\n\n            // Safety: if somehow not at goal, force with baseline (rare)\n            if (cur != goal && (int)answer.size() < 2 * N * M) {\n                vector<Action> fb = shortestFixedPath(blockg, cur, goal);\n                for (auto &ac : fb) {\n                    if ((int)answer.size() >= 2 * N * M) break;\n                    answer.push_back(ac);\n                    applyAction(cur, ac);\n                }\n            }\n\n            if ((int)answer.size() >= 2 * N * M) break;\n        }\n\n        for (auto &ac : answer) {\n            cout << ac.a << ' ' << ac.d << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    cin >> s.N >> s.M;\n    s.P.resize(s.M);\n\n    for (int i = 0; i < 20; i++) for (int j = 0; j < 20; j++) s.ord[i][j] = -1;\n\n    for (int k = 0; k < s.M; k++) {\n        int x, y;\n        cin >> x >> y;\n        s.P[k] = {x, y};\n        s.ord[x][y] = k;\n    }\n\n    s.solve();\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect { int a,b,c,d; }; // [a,c) x [b,d)\n\nstatic inline bool overlap1D(int l1,int r1,int l2,int r2){\n    return max(l1,l2) < min(r1,r2);\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now()-st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32(){ return (uint32_t)next_u64(); }\n    int rand_int(int l,int r){\n        if(l>r) return l;\n        uint64_t range=(uint64_t)(r-l+1);\n        return l + (int)(next_u64()%range);\n    }\n    double rand01(){\n        return (next_u64()>>11) * (1.0/9007199254740992.0);\n    }\n};\n\nstruct PushGroup {\n    int cnt=0;\n    int ids[205];\n    int dmax=0;\n};\n\nstruct State {\n    vector<Rect> rect;\n    vector<double> p;\n    double sumP=0;\n};\n\nstruct SplitChoice {\n    bool ok=false;\n    bool vertical=false;\n    int k=0;        // split coordinate\n    int m=0;        // first part size in sorted order\n    long long err=0; // integer error measure\n    vector<int> leftIds, rightIds;\n};\n\nstruct Candidate {\n    int m;\n    int k;\n    long long err;\n};\n\nstruct Solver {\n    int n;\n    vector<int> x,y;\n    vector<long long> r;\n\n    vector<Rect> rect;\n    vector<double> p;\n    double sumP=0.0;\n\n    SplitMix64 rng;\n    Timer timer;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin>>n;\n        x.resize(n); y.resize(n); r.resize(n);\n        for(int i=0;i<n;i++) cin>>x[i]>>y[i]>>r[i];\n\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = SplitMix64(seed);\n\n        rect.resize(n);\n        p.assign(n,0.0);\n\n        for(int i=0;i<n;i++) rect[i] = {x[i],y[i],x[i]+1,y[i]+1};\n        recompute_all_scores();\n    }\n\n    inline long long area(const Rect& R) const {\n        return 1LL*(R.c-R.a)*(R.d-R.b);\n    }\n    inline bool contains_point(int i,const Rect& R) const {\n        return (R.a<=x[i] && x[i]<R.c && R.b<=y[i] && y[i]<R.d);\n    }\n    inline double satisfaction(int i,const Rect& R) const {\n        if(!contains_point(i,R)) return 0.0;\n        long long s=area(R), ri=r[i];\n        long long mn=min(ri,s), mx=max(ri,s);\n        double ratio = (double)mn/(double)mx;\n        double t = 1.0 - ratio;\n        return 1.0 - t*t;\n    }\n\n    void recompute_all_scores(){\n        sumP=0.0;\n        for(int i=0;i<n;i++){\n            p[i]=satisfaction(i,rect[i]);\n            sumP+=p[i];\n        }\n    }\n\n    inline int pick_bad_rect(int k=4){\n        int best = (int)(rng.next_u32()%n);\n        double bestScore = p[best];\n        for(int t=1;t<k;t++){\n            int i = (int)(rng.next_u32()%n);\n            if(p[i] < bestScore){\n                bestScore = p[i];\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    // ===== single-side move =====\n    // dir: 0=a(left),1=c(right),2=b(down),3=d(up)\n    bool feasible_range(int i,int dir,int &low,int &high) const {\n        const Rect &R=rect[i];\n        if(dir==0 || dir==1){\n            int leftLimit=0, rightLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q=rect[j];\n                if(!overlap1D(R.b,R.d,Q.b,Q.d)) continue;\n                if(Q.c<=R.a) leftLimit=max(leftLimit,Q.c);\n                if(R.c<=Q.a) rightLimit=min(rightLimit,Q.a);\n            }\n            if(dir==0){\n                low=leftLimit;\n                high=min(x[i], R.c-1);\n            }else{\n                low=max(x[i]+1, R.a+1);\n                high=rightLimit;\n            }\n        }else{\n            int downLimit=0, upLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q=rect[j];\n                if(!overlap1D(R.a,R.c,Q.a,Q.c)) continue;\n                if(Q.d<=R.b) downLimit=max(downLimit,Q.d);\n                if(R.d<=Q.b) upLimit=min(upLimit,Q.b);\n            }\n            if(dir==2){\n                low=downLimit;\n                high=min(y[i], R.d-1);\n            }else{\n                low=max(y[i]+1, R.b+1);\n                high=upLimit;\n            }\n        }\n        return low<=high;\n    }\n\n    int desired_side_value(int i,int dir,int low,int high) const {\n        const Rect& R=rect[i];\n        long long ri=r[i];\n        if(dir==0 || dir==1){\n            int h=R.d-R.b;\n            long long desiredW=(ri + h/2)/h;\n            desiredW=max<long long>(1, min<long long>(10000, desiredW));\n            if(dir==0){\n                long long desA=(long long)R.c - desiredW;\n                return (int)max<long long>(low, min<long long>(high, desA));\n            }else{\n                long long desC=(long long)R.a + desiredW;\n                return (int)max<long long>(low, min<long long>(high, desC));\n            }\n        }else{\n            int w=R.c-R.a;\n            long long desiredH=(ri + w/2)/w;\n            desiredH=max<long long>(1, min<long long>(10000, desiredH));\n            if(dir==2){\n                long long desB=(long long)R.d - desiredH;\n                return (int)max<long long>(low, min<long long>(high, desB));\n            }else{\n                long long desD=(long long)R.b + desiredH;\n                return (int)max<long long>(low, min<long long>(high, desD));\n            }\n        }\n    }\n\n    static inline Rect with_side(Rect R,int dir,int val){\n        if(dir==0) R.a=val;\n        else if(dir==1) R.c=val;\n        else if(dir==2) R.b=val;\n        else R.d=val;\n        return R;\n    }\n\n    bool greedy_improve_one_side(int i){\n        double cur=p[i];\n        double best=cur;\n        Rect bestR=rect[i];\n\n        for(int dir=0;dir<4;dir++){\n            int low,high;\n            if(!feasible_range(i,dir,low,high)) continue;\n            int curVal = (dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n            if(low==high && low==curVal) continue;\n\n            int des=desired_side_value(i,dir,low,high);\n            int cand[3]={des,low,high};\n            for(int v: cand){\n                if(v<low||v>high||v==curVal) continue;\n                Rect R2=with_side(rect[i],dir,v);\n                if(R2.a>=R2.c || R2.b>=R2.d) continue;\n                double sc=satisfaction(i,R2);\n                if(sc>best+1e-12){\n                    best=sc; bestR=R2;\n                }\n            }\n        }\n        if(best>cur+1e-12){\n            rect[i]=bestR;\n            sumP += (best - p[i]);\n            p[i]=best;\n            return true;\n        }\n        return false;\n    }\n\n    // ===== group push (touching-only) =====\n    bool compute_push_group(int i,int dir, PushGroup &pg) const {\n        pg.cnt=0; pg.dmax=0;\n        const Rect &I=rect[i];\n\n        if(dir==1){ // right\n            int pos1=10001, pos2=10001;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ak=R.a;\n                if(ak<I.c) continue;\n                if(ak<pos1){\n                    pos2=pos1; pos1=ak;\n                    pg.cnt=0; pg.ids[pg.cnt++]=k;\n                }else if(ak==pos1){\n                    pg.ids[pg.cnt++]=k;\n                }else if(ak<pos2){\n                    pos2=ak;\n                }\n            }\n            if(pos1==10001 || pos1!=I.c) return false;\n            if(pos2==10001) pos2=10000;\n            int expandMax = min(10000 - I.c, pos2 - I.c);\n            int shrinkMax = INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int lim = min(x[k], R.c-1) - R.a;\n                shrinkMax = min(shrinkMax, lim);\n            }\n            pg.dmax = max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n        if(dir==0){ // left\n            int pos1=-1, pos2=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ck=R.c;\n                if(ck>I.a) continue;\n                if(ck>pos1){\n                    pos2=pos1; pos1=ck;\n                    pg.cnt=0; pg.ids[pg.cnt++]=k;\n                }else if(ck==pos1){\n                    pg.ids[pg.cnt++]=k;\n                }else if(ck>pos2){\n                    pos2=ck;\n                }\n            }\n            if(pos1==-1 || pos1!=I.a) return false;\n            if(pos2==-1) pos2=0;\n            int expandMax = I.a - pos2;\n            int shrinkMax = INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int need = max(x[k]+1, R.a+1);\n                int lim = R.c - need;\n                shrinkMax = min(shrinkMax, lim);\n            }\n            pg.dmax = max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n        if(dir==3){ // up\n            int pos1=10001, pos2=10001;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n                int bk=R.b;\n                if(bk<I.d) continue;\n                if(bk<pos1){\n                    pos2=pos1; pos1=bk;\n                    pg.cnt=0; pg.ids[pg.cnt++]=k;\n                }else if(bk==pos1){\n                    pg.ids[pg.cnt++]=k;\n                }else if(bk<pos2){\n                    pos2=bk;\n                }\n            }\n            if(pos1==10001 || pos1!=I.d) return false;\n            if(pos2==10001) pos2=10000;\n            int expandMax = min(10000 - I.d, pos2 - I.d);\n            int shrinkMax = INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int lim = min(y[k], R.d-1) - R.b;\n                shrinkMax = min(shrinkMax, lim);\n            }\n            pg.dmax = max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n        // down\n        int pos1=-1, pos2=-1;\n        for(int k=0;k<n;k++) if(k!=i){\n            const Rect &R=rect[k];\n            if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n            int dk=R.d;\n            if(dk>I.b) continue;\n            if(dk>pos1){\n                pos2=pos1; pos1=dk;\n                pg.cnt=0; pg.ids[pg.cnt++]=k;\n            }else if(dk==pos1){\n                pg.ids[pg.cnt++]=k;\n            }else if(dk>pos2){\n                pos2=dk;\n            }\n        }\n        if(pos1==-1 || pos1!=I.b) return false;\n        if(pos2==-1) pos2=0;\n        int expandMax = I.b - pos2;\n        int shrinkMax = INT_MAX;\n        for(int t=0;t<pg.cnt;t++){\n            int k=pg.ids[t];\n            const Rect &R=rect[k];\n            int need = max(y[k]+1, R.b+1);\n            int lim = R.d - need;\n            shrinkMax = min(shrinkMax, lim);\n        }\n        pg.dmax = max(0, min(expandMax, shrinkMax));\n        return pg.dmax>0;\n    }\n\n    inline void apply_group_push(int i,int dir,const PushGroup &pg,int delta){\n        if(dir==1){\n            rect[i].c += delta;\n            for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].a += delta;\n        }else if(dir==0){\n            rect[i].a -= delta;\n            for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].c -= delta;\n        }else if(dir==3){\n            rect[i].d += delta;\n            for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].b += delta;\n        }else{\n            rect[i].b -= delta;\n            for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].d -= delta;\n        }\n    }\n\n    bool greedy_improve_push_group(int i){\n        double bestGain=0.0;\n        int bestDir=-1, bestDelta=0;\n        PushGroup bestPg;\n\n        for(int dir=0;dir<4;dir++){\n            PushGroup pg;\n            if(!compute_push_group(i,dir,pg)) continue;\n            int dmax=pg.dmax;\n\n            long long ai=area(rect[i]);\n            long long deficit=r[i]-ai;\n            long long per=(dir==0||dir==1)?(rect[i].d-rect[i].b):(rect[i].c-rect[i].a);\n            int desd=1;\n            if(deficit>0) desd=(int)min<long long>(dmax, max<long long>(1, (deficit+per-1)/per));\n\n            int mid = max(1, dmax / max(1, pg.cnt));\n            int cand[4]={1, mid, desd, dmax};\n\n            for(int t=0;t<4;t++){\n                int delta=cand[t];\n                if(delta<1||delta>dmax) continue;\n\n                Rect oldI=rect[i];\n                double oldPi=p[i];\n                Rect oldR[205];\n                double oldP[205];\n                double oldSum=oldPi;\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    oldR[u]=rect[k];\n                    oldP[u]=p[k];\n                    oldSum += oldP[u];\n                }\n\n                apply_group_push(i,dir,pg,delta);\n\n                double newSum = satisfaction(i,rect[i]);\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    newSum += satisfaction(k,rect[k]);\n                }\n\n                rect[i]=oldI;\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    rect[k]=oldR[u];\n                }\n\n                double gain = newSum - oldSum;\n                if(gain > bestGain + 1e-12){\n                    bestGain=gain;\n                    bestDir=dir;\n                    bestDelta=delta;\n                    bestPg=pg;\n                }\n            }\n        }\n\n        if(bestGain > 1e-12){\n            double oldSum = p[i];\n            for(int u=0;u<bestPg.cnt;u++) oldSum += p[bestPg.ids[u]];\n\n            apply_group_push(i,bestDir,bestPg,bestDelta);\n\n            double newSum=0.0;\n            p[i]=satisfaction(i,rect[i]); newSum+=p[i];\n            for(int u=0;u<bestPg.cnt;u++){\n                int k=bestPg.ids[u];\n                p[k]=satisfaction(k,rect[k]);\n                newSum+=p[k];\n            }\n            sumP += (newSum - oldSum);\n            return true;\n        }\n        return false;\n    }\n\n    inline bool greedy_step(int i){\n        if(greedy_improve_one_side(i)) return true;\n        return greedy_improve_push_group(i);\n    }\n\n    // ===== BSP init with better split search =====\n    long long sum_r_ids(const vector<int>& ids) const {\n        long long s=0;\n        for(int i: ids) s += r[i];\n        return s;\n    }\n\n    SplitChoice best_vertical_split(int a,int b,int c,int d, const vector<int>& ids){\n        SplitChoice sc;\n        int w=c-a, h=d-b;\n        if(w<=1 || ids.size()<=1) return sc;\n\n        vector<int> ord=ids;\n        sort(ord.begin(), ord.end(), [&](int i,int j){\n            if(x[i]!=x[j]) return x[i]<x[j];\n            return y[i]<y[j];\n        });\n\n        int sz=(int)ord.size();\n        vector<long long> prefSum(sz+1,0);\n        vector<int> prefMaxX(sz+1,-1);\n        vector<int> sufMinX(sz+1, 100000);\n\n        for(int i=0;i<sz;i++){\n            prefSum[i+1]=prefSum[i]+r[ord[i]];\n            prefMaxX[i+1]=max(prefMaxX[i], x[ord[i]]);\n        }\n        for(int i=sz-1;i>=0;i--){\n            sufMinX[i]=min(sufMinX[i+1], x[ord[i]]);\n        }\n\n        long long total=prefSum[sz];\n        vector<Candidate> cand;\n        cand.reserve(sz);\n\n        for(int m=1;m<sz;m++){\n            long long sumL=prefSum[m];\n            int maxXL=prefMaxX[m];\n            int minXR=sufMinX[m];\n\n            int lo=max(a+1, maxXL+1);\n            int hi=min(c-1, minXR);\n            if(lo>hi) continue;\n\n            // ideal left width ~ w * sumL / total (rounded)\n            long long numer = 1LL*w*sumL;\n            int idealW = (int)((numer + total/2) / total);\n            idealW = max(1, min(w-1, idealW));\n\n            int k = a + idealW;\n            k = max(lo, min(hi, k));\n            int leftW = k - a;\n\n            long long err = llabs(1LL*leftW*total - 1LL*w*sumL);\n            cand.push_back({m,k,err});\n        }\n\n        if(cand.empty()) return sc;\n        sort(cand.begin(), cand.end(), [](const Candidate& A, const Candidate& B){\n            return A.err < B.err;\n        });\n\n        int pickN = min(4, (int)cand.size());\n        int pickIdx = 0;\n        if(rng.rand01() < 0.22) pickIdx = rng.rand_int(0, pickN-1);\n\n        int m=cand[pickIdx].m;\n        int k=cand[pickIdx].k;\n\n        sc.ok=true; sc.vertical=true; sc.k=k; sc.m=m; sc.err=cand[pickIdx].err;\n        sc.leftIds.assign(ord.begin(), ord.begin()+m);\n        sc.rightIds.assign(ord.begin()+m, ord.end());\n        return sc;\n    }\n\n    SplitChoice best_horizontal_split(int a,int b,int c,int d, const vector<int>& ids){\n        SplitChoice sc;\n        int w=c-a, h=d-b;\n        if(h<=1 || ids.size()<=1) return sc;\n\n        vector<int> ord=ids;\n        sort(ord.begin(), ord.end(), [&](int i,int j){\n            if(y[i]!=y[j]) return y[i]<y[j];\n            return x[i]<x[j];\n        });\n\n        int sz=(int)ord.size();\n        vector<long long> prefSum(sz+1,0);\n        vector<int> prefMaxY(sz+1,-1);\n        vector<int> sufMinY(sz+1, 100000);\n\n        for(int i=0;i<sz;i++){\n            prefSum[i+1]=prefSum[i]+r[ord[i]];\n            prefMaxY[i+1]=max(prefMaxY[i], y[ord[i]]);\n        }\n        for(int i=sz-1;i>=0;i--){\n            sufMinY[i]=min(sufMinY[i+1], y[ord[i]]);\n        }\n\n        long long total=prefSum[sz];\n        vector<Candidate> cand;\n        cand.reserve(sz);\n\n        for(int m=1;m<sz;m++){\n            long long sumD=prefSum[m];\n            int maxYD=prefMaxY[m];\n            int minYU=sufMinY[m];\n\n            int lo=max(b+1, maxYD+1);\n            int hi=min(d-1, minYU);\n            if(lo>hi) continue;\n\n            long long numer = 1LL*h*sumD;\n            int idealH = (int)((numer + total/2) / total);\n            idealH = max(1, min(h-1, idealH));\n\n            int k = b + idealH;\n            k = max(lo, min(hi, k));\n            int downH = k - b;\n\n            long long err = llabs(1LL*downH*total - 1LL*h*sumD);\n            cand.push_back({m,k,err});\n        }\n\n        if(cand.empty()) return sc;\n        sort(cand.begin(), cand.end(), [](const Candidate& A, const Candidate& B){\n            return A.err < B.err;\n        });\n\n        int pickN = min(4, (int)cand.size());\n        int pickIdx = 0;\n        if(rng.rand01() < 0.22) pickIdx = rng.rand_int(0, pickN-1);\n\n        int m=cand[pickIdx].m;\n        int k=cand[pickIdx].k;\n\n        sc.ok=true; sc.vertical=false; sc.k=k; sc.m=m; sc.err=cand[pickIdx].err;\n        sc.leftIds.assign(ord.begin(), ord.begin()+m);\n        sc.rightIds.assign(ord.begin()+m, ord.end());\n        return sc;\n    }\n\n    void bsp_build(int a,int b,int c,int d, const vector<int>& ids){\n        if(ids.size()==1){\n            rect[ids[0]]={a,b,c,d};\n            return;\n        }\n        int w=c-a, h=d-b;\n\n        SplitChoice V = best_vertical_split(a,b,c,d,ids);\n        SplitChoice H = best_horizontal_split(a,b,c,d,ids);\n\n        SplitChoice chosen;\n        if(V.ok && H.ok){\n            // mild shape bias: split along longer side slightly preferred when errors similar\n            long long vErr = V.err;\n            long long hErr = H.err;\n            if(w > h) vErr = (vErr*97)/100;\n            else if(h > w) hErr = (hErr*97)/100;\n\n            if(rng.rand01() < 0.08){\n                chosen = (rng.rand01()<0.5 ? V : H);\n            }else{\n                chosen = (vErr <= hErr ? V : H);\n            }\n        }else if(V.ok) chosen=V;\n        else chosen=H;\n\n        if(chosen.vertical){\n            int k=chosen.k;\n            bsp_build(a,b,k,d, chosen.leftIds);\n            bsp_build(k,b,c,d, chosen.rightIds);\n        }else{\n            int k=chosen.k;\n            bsp_build(a,b,c,k, chosen.leftIds);\n            bsp_build(a,k,c,d, chosen.rightIds);\n        }\n    }\n\n    void init_1x1(){\n        for(int i=0;i<n;i++) rect[i]={x[i],y[i],x[i]+1,y[i]+1};\n        recompute_all_scores();\n    }\n\n    void init_bsp(){\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        bsp_build(0,0,10000,10000, ids);\n        recompute_all_scores();\n    }\n\n    void quick_greedy(int steps){\n        for(int it=0; it<steps; it++){\n            int i = (rng.rand01()<0.85) ? pick_bad_rect(4) : (int)(rng.next_u32()%n);\n            greedy_step(i);\n        }\n    }\n\n    State snapshot() const {\n        return State{rect, p, sumP};\n    }\n    void restore(const State& s){\n        rect=s.rect; p=s.p; sumP=s.sumP;\n    }\n\n    // ===== SA =====\n    void simulated_annealing(double timeLimitSec){\n        State best = snapshot();\n\n        const double T0=0.16, T1=0.0022;\n        long long iters=0;\n        double T=T0;\n\n        while(true){\n            if((iters & 4095) == 0){\n                double t = timer.elapsed();\n                if(t >= timeLimitSec) break;\n                double prog = t / timeLimitSec;\n                T = T0 * exp(log(T1/T0) * prog);\n            }\n            iters++;\n\n            int i = (rng.rand01()<0.80) ? pick_bad_rect(4) : (int)(rng.next_u32()%n);\n            bool under = (area(rect[i]) < r[i]);\n            double pushProb = under ? 0.40 : 0.20;\n            bool doPush = (rng.rand01() < pushProb);\n\n            if(!doPush){\n                // single-side move\n                int dir1=(int)(rng.next_u32()&3), dir2=(int)(rng.next_u32()&3);\n                int low1,high1,low2,high2;\n                bool ok1=feasible_range(i,dir1,low1,high1);\n                bool ok2=feasible_range(i,dir2,low2,high2);\n                int dir=-1, low=0, high=0;\n                if(ok1 && ok2){\n                    if((high2-low2) > (high1-low1)){ dir=dir2; low=low2; high=high2; }\n                    else { dir=dir1; low=low1; high=high1; }\n                }else if(ok1){ dir=dir1; low=low1; high=high1; }\n                else if(ok2){ dir=dir2; low=low2; high=high2; }\n                else continue;\n\n                int curVal=(dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n                if(low==high) continue;\n\n                int des=desired_side_value(i,dir,low,high);\n                int candVal;\n                if(rng.rand01()<0.78){\n                    int span=max(1,(high-low)/8);\n                    candVal=des + rng.rand_int(-span, span);\n                    candVal=max(low, min(high, candVal));\n                }else{\n                    candVal=rng.rand_int(low, high);\n                }\n                if(candVal==curVal) continue;\n\n                Rect oldR=rect[i];\n                double oldPi=p[i];\n\n                Rect newR=with_side(oldR,dir,candVal);\n                if(newR.a>=newR.c || newR.b>=newR.d) continue;\n\n                double newPi=satisfaction(i,newR);\n                double diff=newPi-oldPi;\n\n                if(diff>=0 || rng.rand01() < exp(diff/T)){\n                    rect[i]=newR;\n                    p[i]=newPi;\n                    sumP += diff;\n                    if(sumP > best.sumP + 1e-9) best = snapshot();\n                }\n            }else{\n                int dirA=(int)(rng.next_u32()&3), dirB=(int)(rng.next_u32()&3);\n                PushGroup pgA, pgB;\n                bool okA=compute_push_group(i,dirA,pgA);\n                bool okB=compute_push_group(i,dirB,pgB);\n\n                int dir=-1;\n                PushGroup pg;\n                if(okA && okB){\n                    if(pgB.dmax > pgA.dmax){ dir=dirB; pg=pgB; }\n                    else { dir=dirA; pg=pgA; }\n                }else if(okA){ dir=dirA; pg=pgA; }\n                else if(okB){ dir=dirB; pg=pgB; }\n                else continue;\n\n                int dmax=pg.dmax;\n                if(dmax<=0) continue;\n\n                long long deficit = r[i] - area(rect[i]);\n                long long per=(dir==0||dir==1)?(rect[i].d-rect[i].b):(rect[i].c-rect[i].a);\n                int desd=1;\n                if(deficit>0) desd=(int)min<long long>(dmax, max<long long>(1, (deficit+per-1)/per));\n\n                int span = max(1, dmax / (8 + pg.cnt));\n                int delta;\n                if(rng.rand01()<0.80){\n                    delta = desd + rng.rand_int(-span, span);\n                    delta = max(1, min(dmax, delta));\n                }else{\n                    delta = rng.rand_int(1, dmax);\n                }\n\n                Rect oldI=rect[i];\n                double oldPi=p[i];\n                Rect oldR[205];\n                double oldP[205];\n                double oldSum=oldPi;\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    oldR[u]=rect[k];\n                    oldP[u]=p[k];\n                    oldSum += oldP[u];\n                }\n\n                apply_group_push(i,dir,pg,delta);\n\n                double newPi=satisfaction(i,rect[i]);\n                double newSum=newPi;\n                double newGroupP[205];\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    newGroupP[u]=satisfaction(k,rect[k]);\n                    newSum += newGroupP[u];\n                }\n\n                double diff = newSum - oldSum;\n                if(diff>=0 || rng.rand01() < exp(diff/T)){\n                    p[i]=newPi;\n                    for(int u=0;u<pg.cnt;u++){\n                        int k=pg.ids[u];\n                        p[k]=newGroupP[u];\n                    }\n                    sumP += diff;\n                    if(sumP > best.sumP + 1e-9) best = snapshot();\n                }else{\n                    rect[i]=oldI;\n                    p[i]=oldPi;\n                    for(int u=0;u<pg.cnt;u++){\n                        int k=pg.ids[u];\n                        rect[k]=oldR[u];\n                        p[k]=oldP[u];\n                    }\n                }\n            }\n        }\n\n        restore(best);\n    }\n\n    void solve(){\n        const double HARD_LIMIT = 4.93;   // time safety margin\n        const double INIT_BUDGET = 1.20;  // spend up to this on multi-init\n\n        State best; best.sumP = -1e100;\n\n        auto consider = [&](){\n            if(sumP > best.sumP + 1e-12) best = snapshot();\n        };\n\n        // baseline init\n        init_1x1();\n        quick_greedy(8000);\n        consider();\n\n        // several BSP inits within budget\n        int bspTries=0;\n        while(bspTries < 8 && timer.elapsed() < INIT_BUDGET){\n            init_bsp();\n            quick_greedy(8000);\n            consider();\n            bspTries++;\n        }\n\n        restore(best);\n\n        // SA until HARD_LIMIT\n        if(timer.elapsed() < HARD_LIMIT - 0.05){\n            simulated_annealing(HARD_LIMIT);\n        }\n\n        // small final greedy if time remains (bounded by HARD_LIMIT-0.01)\n        double endGreedy = HARD_LIMIT - 0.01;\n        int it = 0;\n        while(timer.elapsed() < endGreedy && it < 7000){\n            int i = pick_bad_rect(6);\n            greedy_step(i);\n            it++;\n        }\n\n        for(int i=0;i<n;i++){\n            cout<<rect[i].a<<' '<<rect[i].b<<' '<<rect[i].c<<' '<<rect[i].d<<\"\\n\";\n        }\n    }\n};\n\nint main(){\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50, W = 50, N = H * W;\nstatic constexpr int MAXM = 2500;\nstatic constexpr int BSZ = (MAXM + 63) / 64;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463325252ULL) {}\n    inline uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); } // inclusive\n};\n\nstruct TileSet {\n    array<uint64_t, BSZ> b{};\n    inline void clear() { b.fill(0); }\n    inline bool test(int i) const { return (b[i >> 6] >> (i & 63)) & 1ULL; }\n    inline void set1(int i) { b[i >> 6] |= (1ULL << (i & 63)); }\n    inline void reset1(int i) { b[i >> 6] &= ~(1ULL << (i & 63)); }\n};\n\nstruct State {\n    vector<int> path;      // squares\n    vector<int> tileStack; // tile ids parallel to path\n    TileSet used;\n    int score = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    cin >> si >> sj;\n    const int start = si * W + sj;\n\n    vector<int> tile(N);\n    int maxTile = 0;\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int t; cin >> t;\n        tile[i * W + j] = t;\n        maxTile = max(maxTile, t);\n    }\n    const int M = maxTile + 1;\n\n    vector<int> val(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int p; cin >> p;\n        val[i * W + j] = p;\n    }\n\n    // Square adjacency excluding same-tile moves\n    array<array<int, 4>, N> nbr;\n    array<uint8_t, N> deg{};\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        uint8_t d = 0;\n        auto add = [&](int ni, int nj) {\n            if (ni < 0 || ni >= H || nj < 0 || nj >= W) return;\n            int v = ni * W + nj;\n            if (tile[u] == tile[v]) return;\n            nbr[u][d++] = v;\n        };\n        add(i - 1, j); add(i + 1, j); add(i, j - 1); add(i, j + 1);\n        deg[u] = d;\n    }\n\n    // Tile adjacency graph\n    vector<vector<int>> tadj(M);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        int tu = tile[u];\n        if (j + 1 < W) {\n            int v = i * W + (j + 1);\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n        if (i + 1 < H) {\n            int v = (i + 1) * W + j;\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n    }\n    for (int t = 0; t < M; t++) {\n        auto &v = tadj[t];\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n    }\n\n    auto deg_square = [&](int sq, const TileSet &used) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            if (!used.test(tile[to])) d++;\n        }\n        return d;\n    };\n    auto deg_square_forbid_tile = [&](int sq, const TileSet &used, int forbidTile) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            int tt = tile[to];\n            if (tt == forbidTile) continue;\n            if (!used.test(tt)) d++;\n        }\n        return d;\n    };\n    auto deg_tile_unvisited = [&](int t, const TileSet &used) -> int {\n        int d = 0;\n        for (int nx : tadj[t]) if (!used.test(nx)) d++;\n        return d;\n    };\n    auto deg_tile_unvisited_forbid = [&](int t, const TileSet &used, int forbidTile) -> int {\n        int d = 0;\n        for (int nx : tadj[t]) if (nx != forbidTile && !used.test(nx)) d++;\n        return d;\n    };\n    // very cheap 2-hop proxy (no BFS): sum of neighbor tile degrees excluding back-edge\n    auto tile_2hop = [&](int t, const TileSet &used) -> int {\n        int s = 0;\n        for (int u : tadj[t]) {\n            if (used.test(u)) continue;\n            s += deg_tile_unvisited_forbid(u, used, t);\n        }\n        return s;\n    };\n\n    auto extend_greedy = [&](State &st, XorShift64 &rng,\n                            double a1, double a2, double a3, double g,\n                            double deadPenalty,\n                            double pocket0Penalty, double pocket1Penalty) {\n        while (true) {\n            int cur = st.path.back();\n\n            int cand[4];\n            int cm = 0;\n            for (int k = 0; k < (int)deg[cur]; k++) {\n                int to = nbr[cur][k];\n                if (!st.used.test(tile[to])) cand[cm++] = to;\n            }\n            if (cm == 0) break;\n\n            // avoid choosing immediate dead-end if any non-dead-end exists\n            int d1[4];\n            bool anyNonDead = false;\n            for (int i = 0; i < cm; i++) {\n                d1[i] = deg_square(cand[i], st.used);\n                if (d1[i] > 0) anyNonDead = true;\n            }\n\n            struct Item { int sq; double sc; };\n            Item items[4];\n            int im = 0;\n\n            for (int i = 0; i < cm; i++) {\n                int nx = cand[i];\n                int dn1 = d1[i];\n                if (anyNonDead && dn1 == 0) continue;\n\n                int tn = tile[nx];\n                int dt = deg_tile_unvisited(tn, st.used);\n                int t2 = (a3 != 0.0 ? tile_2hop(tn, st.used) : 0);\n\n                // 2-step lookahead best2\n                double best2 = 0.0;\n                for (int k = 0; k < (int)deg[nx]; k++) {\n                    int nn = nbr[nx][k];\n                    int tnn = tile[nn];\n                    if (st.used.test(tnn)) continue;\n                    int d2 = deg_square_forbid_tile(nn, st.used, tn);\n                    int dt2 = deg_tile_unvisited_forbid(tnn, st.used, tn);\n                    double s2 = val[nn] + a1 * d2 + 0.50 * a2 * dt2;\n                    if (s2 > best2) best2 = s2;\n                }\n\n                double sc = 0.0;\n                sc += val[nx];\n                sc += a1 * dn1;\n                sc += a2 * dt;\n                sc += a3 * t2;     // small effect only\n                sc += g * best2;\n\n                // pocket-avoidance: penalize stepping into tiles with tiny tile-degree\n                if (dt == 0) sc -= pocket0Penalty;\n                else if (dt == 1) sc -= pocket1Penalty;\n\n                if (dn1 == 0) sc -= deadPenalty;\n\n                // tiny noise\n                sc += rng.next_double() * 1e-3;\n\n                items[im++] = {nx, sc};\n            }\n\n            if (im == 0) break;\n\n            // sort desc (im<=4)\n            for (int i = 0; i < im; i++) {\n                int best = i;\n                for (int j = i + 1; j < im; j++) if (items[j].sc > items[best].sc) best = j;\n                swap(items[i], items[best]);\n            }\n\n            // randomized top-k pick\n            int pick = 0;\n            double u = rng.next_double();\n            if (im >= 2) {\n                if (u < 0.80) pick = 0;\n                else if (u < 0.95) pick = 1;\n                else pick = min(2, im - 1);\n            }\n\n            int nxt = items[pick].sq;\n            int tnx = tile[nxt];\n            st.used.set1(tnx);\n            st.path.push_back(nxt);\n            st.tileStack.push_back(tnx);\n            st.score += val[nxt];\n        }\n    };\n\n    auto build_one = [&](XorShift64 &rng) -> State {\n        State st;\n        st.used.clear();\n        st.path.reserve(N);\n        st.tileStack.reserve(N);\n\n        st.path.push_back(start);\n        st.tileStack.push_back(tile[start]);\n        st.used.set1(tile[start]);\n        st.score = val[start];\n\n        // Base parameters (close to your best-performing family)\n        double a1 = 7.0 + 20.0 * rng.next_double();   // square mobility\n        double a2 = 1.0 + 11.0 * rng.next_double();   // tile mobility\n\n        // a3 is gated: often 0, sometimes small (prevents noisy domination)\n        double a3 = 0.0;\n        if (rng.next_double() < 0.35) a3 = 0.10 + 0.90 * rng.next_double(); // [0.10,1.00]\n\n        double g  = 0.08 + 0.62 * rng.next_double();  // lookahead\n        double dp = 22.0 + 55.0 * rng.next_double();  // dead-end penalty\n\n        double p0 = 18.0 + 45.0 * rng.next_double();  // dt==0 penalty\n        double p1 =  5.0 + 25.0 * rng.next_double();  // dt==1 penalty\n\n        extend_greedy(st, rng, a1, a2, a3, g, dp, p0, p1);\n        return st;\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto now = [&]() { return chrono::steady_clock::now(); };\n    const double TL = 1.95;\n\n    XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Initial multi-start\n    State best = build_one(rng);\n    while (chrono::duration<double>(now() - t0).count() < 0.30) {\n        State s = build_one(rng);\n        if (s.score > best.score) best = std::move(s);\n    }\n    State cur = best;\n\n    vector<int> removedSq, removedTile;\n    removedSq.reserve(N);\n    removedTile.reserve(N);\n\n    int it = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > TL) break;\n        it++;\n\n        if (it % 2600 == 0) cur = best;\n\n        int L = (int)cur.path.size();\n        if (L <= 1) continue;\n\n        // Cut position distribution (mix tail cuts + occasional global shake)\n        int k;\n        double r = rng.next_double();\n        if (r < 0.03) k = 0;                           // full rebuild\n        else if (r < 0.15) k = rng.next_int(0, L - 2); // global cut\n        else if (r < 0.75) {\n            int lo = max(0, L - 1 - 260);\n            k = rng.next_int(lo, L - 2);\n        } else {\n            int lo = max(0, L - 1 - 700);\n            k = rng.next_int(lo, L - 2);\n        }\n\n        int origScore = cur.score;\n\n        removedSq.clear();\n        removedTile.clear();\n        while ((int)cur.path.size() > k + 1) {\n            int sq = cur.path.back(); cur.path.pop_back();\n            int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n            cur.used.reset1(tid);\n            cur.score -= val[sq];\n            removedSq.push_back(sq);\n            removedTile.push_back(tid);\n        }\n\n        // Regrow with fresh params\n        double a1 = 6.5 + 21.5 * rng.next_double();\n        double a2 = 1.0 + 12.0 * rng.next_double();\n        double a3 = 0.0;\n        if (rng.next_double() < 0.40) a3 = 0.05 + 1.10 * rng.next_double();\n\n        double g  = 0.05 + 0.68 * rng.next_double();\n        double dp = 20.0 + 60.0 * rng.next_double();\n\n        double p0 = 15.0 + 55.0 * rng.next_double();\n        double p1 =  4.0 + 30.0 * rng.next_double();\n\n        extend_greedy(cur, rng, a1, a2, a3, g, dp, p0, p1);\n\n        int delta = cur.score - origScore;\n\n        // SA acceptance\n        double tr = elapsed / TL;\n        double T0 = 420.0, Tend = 2.0;\n        double T = T0 * pow(Tend / T0, tr);\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            // remove newly added suffix\n            while ((int)cur.path.size() > k + 1) {\n                int sq = cur.path.back(); cur.path.pop_back();\n                int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n                cur.used.reset1(tid);\n                cur.score -= val[sq];\n            }\n            // restore old suffix\n            for (int i = (int)removedSq.size() - 1; i >= 0; i--) {\n                int sq = removedSq[i];\n                int tid = removedTile[i];\n                cur.path.push_back(sq);\n                cur.tileStack.push_back(tid);\n                cur.used.set1(tid);\n                cur.score += val[sq];\n            }\n        } else {\n            if (cur.score > best.score) best = cur;\n        }\n    }\n\n    // Output directions\n    string out;\n    out.reserve(best.path.size() ? best.path.size() - 1 : 0);\n    for (int i = 1; i < (int)best.path.size(); i++) {\n        int a = best.path[i - 1], b = best.path[i];\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (bi == ai - 1 && bj == aj) out.push_back('U');\n        else if (bi == ai + 1 && bj == aj) out.push_back('D');\n        else if (bi == ai && bj == aj - 1) out.push_back('L');\n        else if (bi == ai && bj == aj + 1) out.push_back('R');\n        else break; // should not happen\n    }\n    cout << out << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horiz; // true: horizontal h[i][j], false: vertical v[i][j]\n    int i, j;\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int HW = 29;\nstatic constexpr int VH = 29;\n\nstruct PathInfo {\n    vector<int> nodes;\n    vector<EdgeRef> edges;\n    string moves;\n    double base_sum = 0.0; // sum of current base weights along this path\n};\n\nstruct Solver {\n    double h[N][HW];\n    double v[VH][N];\n    int hc[N][HW];\n    int vc[VH][N];\n\n    vector<EdgeRef> last_edges;\n    double last_pred = 1.0;\n    int k = 0;\n\n    Solver() {\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n            h[i][j] = 5000.0;\n            hc[i][j] = 0;\n        }\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n            v[i][j] = 5000.0;\n            vc[i][j] = 0;\n        }\n    }\n\n    static inline double clampd(double x, double lo, double hi) {\n        return (x < lo) ? lo : (x > hi) ? hi : x;\n    }\n\n    inline double &wref(const EdgeRef &e) { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int &cref(const EdgeRef &e) { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n    inline double wval(const EdgeRef &e) const { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int cval(const EdgeRef &e) const { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n\n    inline EdgeRef edgeBetween(int u, int w) const {\n        int ui = u / N, uj = u % N;\n        int wi = w / N, wj = w % N;\n        if (ui == wi) {\n            if (wj == uj + 1) return {true, ui, uj};\n            else return {true, ui, wj}; // wj==uj-1\n        } else {\n            if (wi == ui + 1) return {false, ui, uj};\n            else return {false, wi, uj}; // wi==ui-1\n        }\n    }\n\n    inline double baseEdgeWeight(const EdgeRef &e) const {\n        return clampd(wval(e), 500.0, 12000.0);\n    }\n\n    // Planning weight = base * pessimism / exploration.\n    // Pessimism grows late to avoid unknown edges; exploration exists only early and only for explore candidate.\n    inline double planWeight(const EdgeRef &e, int qk, double explore_scale) const {\n        double base = baseEdgeWeight(e);\n        int cnt = cval(e);\n\n        double phase = (qk < 280) ? (280.0 - qk) / 280.0 : 0.0; // 1 -> 0\n        double explore = explore_scale * phase;                 // only early\n        double pess = 0.04 + 0.26 * (1.0 - phase);              // moderate (not too conservative)\n\n        double s = sqrt(cnt + 1.0);\n        double factor = (1.0 + pess / s) / (1.0 + explore / s);\n        return clampd(base * factor, 500.0, 12000.0);\n    }\n\n    vector<int> dijkstraPath(int si, int sj, int ti, int tj, int qk, double explore_scale) const {\n        int s = si * N + sj;\n        int t = ti * N + tj;\n\n        vector<double> dist(N * N, 1e100);\n        vector<int> prev(N * N, -1);\n        using P = pair<double,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == t) break;\n\n            int ui = u / N, uj = u % N;\n            auto relax = [&](int w) {\n                EdgeRef e = edgeBetween(u, w);\n                double ww = planWeight(e, qk, explore_scale);\n                double nd = d + ww;\n                if (nd < dist[w]) {\n                    dist[w] = nd;\n                    prev[w] = u;\n                    pq.push({nd, w});\n                }\n            };\n\n            if (uj + 1 < N) relax(u + 1);\n            if (uj - 1 >= 0) relax(u - 1);\n            if (ui + 1 < N) relax(u + N);\n            if (ui - 1 >= 0) relax(u - N);\n        }\n\n        vector<int> nodes;\n        for (int cur = t; cur != -1; cur = prev[cur]) {\n            nodes.push_back(cur);\n            if (cur == s) break;\n        }\n        reverse(nodes.begin(), nodes.end());\n        return nodes;\n    }\n\n    PathInfo buildPathInfo(const vector<int> &nodes) const {\n        PathInfo info;\n        info.nodes = nodes;\n        if (nodes.empty()) return info;\n\n        info.moves.reserve(nodes.size() - 1);\n        info.edges.reserve(nodes.size() - 1);\n        info.base_sum = 0.0;\n\n        for (int idx = 0; idx + 1 < (int)nodes.size(); idx++) {\n            int a = nodes[idx], b = nodes[idx + 1];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            if (bi == ai && bj == aj + 1) info.moves.push_back('R');\n            else if (bi == ai && bj == aj - 1) info.moves.push_back('L');\n            else if (bi == ai + 1 && bj == aj) info.moves.push_back('D');\n            else if (bi == ai - 1 && bj == aj) info.moves.push_back('U');\n            else info.moves.push_back('R');\n\n            EdgeRef e = edgeBetween(a, b);\n            info.edges.push_back(e);\n            info.base_sum += baseEdgeWeight(e);\n        }\n\n        info.base_sum = max(info.base_sum, 1.0);\n        return info;\n    }\n\n    // Destructive piecewise shrink, but ONLY for low-count edges to avoid harming learned structure.\n    void denoisePiecewise() {\n        auto fit1d = [&](int L,\n                         function<double(int)> getW,\n                         function<int(int)> getC,\n                         function<void(int,double)> setW) {\n            vector<double> y(L), wt(L);\n            for (int i = 0; i < L; i++) {\n                double w = clampd(getW(i), 500.0, 12000.0);\n                y[i] = log(w);\n                double c = (double)getC(i);\n                wt[i] = 0.05 + min(1.0, c / 5.0);\n            }\n\n            vector<double> prefW(L+1,0), prefWY(L+1,0), prefWY2(L+1,0);\n            for (int i = 0; i < L; i++) {\n                prefW[i+1]   = prefW[i]   + wt[i];\n                prefWY[i+1]  = prefWY[i]  + wt[i]*y[i];\n                prefWY2[i+1] = prefWY2[i] + wt[i]*y[i]*y[i];\n            }\n\n            auto segSSE = [&](int l, int r)->pair<double,double>{\n                double W = prefW[r] - prefW[l];\n                double WY = prefWY[r] - prefWY[l];\n                double WY2 = prefWY2[r] - prefWY2[l];\n                if (W <= 1e-12) return {0.0, log(5000.0)};\n                double m = WY / W;\n                double sse = WY2 - 2*m*WY + m*m*W;\n                return {sse, m};\n            };\n\n            auto [sse1, m1] = segSSE(0, L);\n\n            double bestSSE2 = sse1;\n            int bestX = -1;\n            double bestML = m1, bestMR = m1;\n\n            for (int x = 1; x <= L-1; x++) {\n                double WL = prefW[x], WR = prefW[L] - prefW[x];\n                if (WL < 0.6 || WR < 0.6) continue;\n                auto [sseL, mL] = segSSE(0, x);\n                auto [sseR, mR] = segSSE(x, L);\n                double sse2 = sseL + sseR;\n                if (sse2 < bestSSE2) {\n                    bestSSE2 = sse2;\n                    bestX = x;\n                    bestML = mL;\n                    bestMR = mR;\n                }\n            }\n\n            double totalW = prefW[L];\n            bool use2 = false;\n            if (bestX != -1) {\n                double improve = sse1 - bestSSE2;\n                if (improve > 0.010 * totalW) use2 = true;\n            }\n\n            // shrink only low-count edges\n            for (int i = 0; i < L; i++) {\n                int c = getC(i);\n                if (c >= 7) continue; // do not touch well-learned edges\n\n                double target = m1;\n                if (use2) target = (i < bestX) ? bestML : bestMR;\n\n                // stronger shrink for smaller count\n                double baseLam = 0.12 / sqrt(c + 1.0);\n                double scale = (7.0 - c) / 7.0; // cnt 0 => 1, cnt 6 => ~0.14\n                double lam = min(0.22, baseLam * scale);\n\n                double ny = (1.0 - lam) * y[i] + lam * target;\n                setW(i, clampd(exp(ny), 500.0, 12000.0));\n            }\n        };\n\n        // fit rows (horizontal)\n        for (int r = 0; r < N; r++) {\n            fit1d(HW,\n                  [&](int j){ return h[r][j]; },\n                  [&](int j){ return hc[r][j]; },\n                  [&](int j, double val){ h[r][j] = val; });\n        }\n        // fit cols (vertical) along i\n        for (int c = 0; c < N; c++) {\n            fit1d(VH,\n                  [&](int i){ return v[i][c]; },\n                  [&](int i){ return vc[i][c]; },\n                  [&](int i, double val){ v[i][c] = val; });\n        }\n    }\n\n    string query(int si, int sj, int ti, int tj) {\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        // exploit candidate\n        auto nodes_exploit = dijkstraPath(si, sj, ti, tj, k, 0.0);\n        auto info_exploit = buildPathInfo(nodes_exploit);\n\n        // explore candidate\n        auto nodes_explore = dijkstraPath(si, sj, ti, tj, k, 0.55);\n        auto info_explore = buildPathInfo(nodes_explore);\n\n        // choose exploration only if not much worse in predicted base_sum\n        double phase = (k < 280) ? (280.0 - k) / 280.0 : 0.0;\n        double margin = 0.025 + 0.085 * phase; // early ~11%, late ~2.5%\n\n        bool explore_ok = true;\n        if ((int)info_explore.nodes.size() - 1 > manhattan + 75) explore_ok = false;\n\n        const PathInfo *chosen = &info_exploit;\n        if (explore_ok && info_explore.base_sum <= info_exploit.base_sum * (1.0 + margin)) {\n            chosen = &info_explore;\n        }\n\n        last_edges = chosen->edges;\n        last_pred  = chosen->base_sum;\n        return chosen->moves;\n    }\n\n    void feedback(long long observed) {\n        if (last_edges.empty()) { k++; return; }\n\n        // dynamic clamp for robustness\n        double lo, hi;\n        if (k < 40) { lo = 0.70; hi = 1.40; }\n        else if (k < 180) {\n            double a = (k - 40) / 140.0;\n            lo = 0.70 + a * (0.85 - 0.70);\n            hi = 1.40 + a * (1.18 - 1.40);\n        } else {\n            lo = 0.85; hi = 1.18;\n        }\n\n        double ratio = (double)observed / last_pred;\n        ratio = clampd(ratio, lo, hi);\n        double logratio = log(ratio);\n\n        // learning schedule\n        double t = (double)k / 1000.0;\n        double base_lr = 0.85 * (1.0 - t) + 0.25;\n\n        // denom = sum(share^2 * damp)\n        double denom = 0.0;\n        for (auto &e : last_edges) {\n            double w = baseEdgeWeight(e);\n            double share = w / last_pred;\n            double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n            denom += share * share * damp;\n        }\n        denom = max(denom, 1e-12);\n        double alpha = base_lr / denom;\n\n        for (auto &e : last_edges) {\n            double w = baseEdgeWeight(e);\n            double share = w / last_pred;\n            double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n\n            double dx = alpha * logratio * share * damp;\n            dx = clampd(dx, -0.28, 0.28);\n\n            double &ww = wref(e);\n            ww *= exp(dx);\n            ww = clampd(ww, 500.0, 12000.0);\n\n            cref(e)++;\n        }\n\n        // structured denoise periodically (reduced frequency)\n        if (k >= 90 && (k % 28 == 27)) denoisePiecewise();\n\n        k++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    for (int q = 0; q < 1000; q++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        string path = solver.query(si, sj, ti, tj);\n        cout << path << \"\\n\" << flush;\n\n        long long res;\n        cin >> res;\n        solver.feedback(res);\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr uint8_t DOT = 8; // only used in dot pruning\n\n// ---------- RNG (splitmix64) ----------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Hasher {\n    size_t operator()(uint64_t x) const noexcept {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        x ^= (x >> 31);\n        return (size_t)x;\n    }\n};\nusing FlatMap = boost::unordered_flat_map<uint64_t, int, Hasher>;\n\n// code = (len<<36) | bits (3 bits per char)\nstatic inline uint64_t encodeVec(const vector<uint8_t>& v, int st, int len) {\n    uint64_t bits = 0;\n    for (int i = 0; i < len; i++) bits = (bits << 3) | (uint64_t)v[st + i];\n    return (uint64_t(len) << 36) | bits;\n}\nstatic inline uint64_t encodeFull(const vector<uint8_t>& v) {\n    return encodeVec(v, 0, (int)v.size());\n}\nstatic inline vector<uint8_t> decodeCode(uint64_t code) {\n    int len = int(code >> 36);\n    vector<uint8_t> v(len);\n    uint64_t bits = code & ((len == 0) ? 0ULL : ((1ULL << (3 * len)) - 1ULL));\n    for (int i = len - 1; i >= 0; i--) {\n        v[i] = uint8_t(bits & 7ULL);\n        bits >>= 3;\n    }\n    return v;\n}\n\nstruct CodeBook {\n    int minLen = 2, maxLen = 12;\n    FlatMap code2idx;\n    vector<int> weight;                 // multiplicity per unique code\n    vector<uint64_t> codes;             // code per idx\n    vector<vector<uint8_t>> pattern;    // decoded patterns (only for full objective)\n    vector<int> impPriority;            // priority for selecting uncovered strings (only full)\n    long long totalWeight = 0;\n};\n\nstatic CodeBook makeCodeBook(const FlatMap& wmap, int minLen, int maxLen, bool storePattern) {\n    CodeBook book;\n    book.minLen = minLen;\n    book.maxLen = maxLen;\n\n    book.code2idx.reserve(wmap.size() * 2 + 8);\n    book.code2idx.max_load_factor(0.70f);\n\n    book.weight.reserve(wmap.size());\n    book.codes.reserve(wmap.size());\n\n    int idx = 0;\n    long long sum = 0;\n    for (auto &kv : wmap) {\n        uint64_t code = kv.first;\n        int len = int(code >> 36);\n        if (len < minLen || len > maxLen) continue;\n        int w = kv.second;\n        book.code2idx.emplace(code, idx++);\n        book.codes.push_back(code);\n        book.weight.push_back(w);\n        sum += w;\n    }\n    book.totalWeight = sum;\n\n    if (storePattern) {\n        int sz = (int)book.codes.size();\n        book.pattern.resize(sz);\n        book.impPriority.resize(sz);\n        for (int i = 0; i < sz; i++) {\n            book.pattern[i] = decodeCode(book.codes[i]);\n            int L = (int)book.pattern[i].size();\n            long long p = 1LL * L * L * L * book.weight[i]; // long & frequent first\n            if (p > INT_MAX) p = INT_MAX;\n            book.impPriority[i] = (int)p;\n        }\n    }\n    return book;\n}\n\n// ---------- incremental state ----------\nstruct SAState {\n    array<array<uint8_t, N>, N>* mat = nullptr;\n    const CodeBook* book = nullptr;\n\n    vector<int> occ;                 // occurrences across all 40 lines\n    long long score = 0;             // sum weight[idx] if occ[idx]>0\n    array<vector<int>, 40> lineIdx;  // matched idx list per line (with multiplicity)\n\n    vector<int> tmpA, tmpB;\n\n    SAState() {\n        tmpA.reserve(256);\n        tmpB.reserve(256);\n        for (auto &v : lineIdx) v.reserve(256);\n    }\n\n    inline void getLineSeq(int lineId, uint8_t seq[N]) const {\n        if (lineId < 20) {\n            int r = lineId;\n            for (int c = 0; c < N; c++) seq[c] = (*mat)[r][c];\n        } else {\n            int c = lineId - 20;\n            for (int r = 0; r < N; r++) seq[r] = (*mat)[r][c];\n        }\n    }\n\n    inline void computeLineInto(int lineId, vector<int>& out) const {\n        out.clear();\n        uint8_t seq[N];\n        getLineSeq(lineId, seq);\n\n        const int minL = book->minLen;\n        const int maxL = book->maxLen;\n\n        for (int st = 0; st < N; st++) {\n            uint64_t bits = 0;\n            int pos = st;\n            for (int l = 1; l <= maxL; l++) {\n                uint8_t v = seq[pos];\n                if (v == DOT) break;\n                bits = (bits << 3) | (uint64_t)v;\n                if (l >= minL) {\n                    uint64_t code = (uint64_t(l) << 36) | bits;\n                    auto it = book->code2idx.find(code);\n                    if (it != book->code2idx.end()) out.push_back(it->second);\n                }\n                pos++;\n                if (pos == N) pos = 0;\n            }\n        }\n    }\n\n    inline void replaceSwapLine(int lineId, vector<int>& newVec) {\n        for (int idx : lineIdx[lineId]) {\n            int &x = occ[idx];\n            x--;\n            if (x == 0) score -= book->weight[idx];\n        }\n        for (int idx : newVec) {\n            int &x = occ[idx];\n            if (x == 0) score += book->weight[idx];\n            x++;\n        }\n        lineIdx[lineId].swap(newVec);\n    }\n\n    void init(array<array<uint8_t, N>, N> &m, const CodeBook& b) {\n        mat = &m;\n        book = &b;\n        occ.assign(book->codes.size(), 0);\n        score = 0;\n        for (int lineId = 0; lineId < 40; lineId++) {\n            vector<int> tmp;\n            tmp.reserve(256);\n            computeLineInto(lineId, tmp);\n            lineIdx[lineId] = std::move(tmp);\n            for (int idx : lineIdx[lineId]) {\n                int &x = occ[idx];\n                if (x == 0) score += book->weight[idx];\n                x++;\n            }\n        }\n        tmpA.clear(); tmpB.clear();\n        tmpA.reserve(256); tmpB.reserve(256);\n    }\n};\n\nstruct Solver {\n    int M;\n    vector<vector<uint8_t>> inputs;\n    RNG rng;\n    array<array<uint8_t, N>, N> mat;\n    chrono::steady_clock::time_point startTime;\n\n    explicit Solver(int M) : M(M) {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = RNG(seed);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    inline double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void initByFreq() {\n        array<long long, 8> freq{};\n        long long tot = 0;\n        for (auto &s : inputs) for (uint8_t v : s) { freq[v]++; tot++; }\n        if (tot == 0) return;\n\n        vector<double> acc(8);\n        double sum = 0;\n        for (int i = 0; i < 8; i++) sum += (double)freq[i] + 1.0;\n        double cur = 0;\n        for (int i = 0; i < 8; i++) { cur += ((double)freq[i] + 1.0) / sum; acc[i] = cur; }\n\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            double r = rng.nextDouble();\n            int v = 0;\n            while (v < 7 && r > acc[v]) v++;\n            mat[i][j] = (uint8_t)v;\n        }\n        for (int t = 0; t < 10; t++) mat[rng.nextInt(0, N - 1)][rng.nextInt(0, N - 1)] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    struct CellCh { int r, c; uint8_t oldv; };\n\n    bool tryApplyCells(SAState& st, const vector<CellCh>& changes, double T) {\n        if (changes.empty()) return false;\n\n        bool mark[40] = {};\n        int lids[40], lidCount = 0;\n        auto addLine = [&](int id) { if (!mark[id]) { mark[id] = true; lids[lidCount++] = id; } };\n        for (auto &ch : changes) { addLine(ch.r); addLine(20 + ch.c); }\n\n        long long oldScore = st.score;\n\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n\n        vector<int> tmp;\n        tmp.reserve(256);\n\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            tmp.clear();\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp); // tmp now old vector\n            backups.emplace_back(lid, vector<int>());\n            backups.back().second.swap(tmp);\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            for (int k = (int)backups.size() - 1; k >= 0; k--) st.replaceSwapLine(backups[k].first, backups[k].second);\n            for (auto &ch : changes) mat[ch.r][ch.c] = ch.oldv;\n        }\n        return accept;\n    }\n\n    bool tryRotate(SAState& st, bool rotateRow, int id, int shift, double T) {\n        shift %= N;\n        if (shift < 0) shift += N;\n        if (shift == 0) return false;\n\n        array<uint8_t, N> buf{};\n        if (rotateRow) {\n            for (int c = 0; c < N; c++) buf[c] = mat[id][c];\n            for (int c = 0; c < N; c++) mat[id][(c + shift) % N] = buf[c];\n        } else {\n            for (int r = 0; r < N; r++) buf[r] = mat[r][id];\n            for (int r = 0; r < N; r++) mat[(r + shift) % N][id] = buf[r];\n        }\n\n        int lids[21], lidCount = 0;\n        if (rotateRow) {\n            lids[lidCount++] = id;\n            for (int c = 0; c < N; c++) lids[lidCount++] = 20 + c;\n        } else {\n            lids[lidCount++] = 20 + id;\n            for (int r = 0; r < N; r++) lids[lidCount++] = r;\n        }\n\n        long long oldScore = st.score;\n\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n\n        vector<int> tmp;\n        tmp.reserve(256);\n\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            tmp.clear();\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp);\n            backups.emplace_back(lid, vector<int>());\n            backups.back().second.swap(tmp);\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            for (int k = (int)backups.size() - 1; k >= 0; k--) st.replaceSwapLine(backups[k].first, backups[k].second);\n            if (rotateRow) for (int c = 0; c < N; c++) mat[id][c] = buf[c];\n            else for (int r = 0; r < N; r++) mat[r][id] = buf[r];\n        }\n        return accept;\n    }\n\n    bool doCellMutate(SAState& st, double T) {\n        int i = rng.nextInt(0, N - 1);\n        int j = rng.nextInt(0, N - 1);\n        uint8_t oldv = mat[i][j];\n        uint8_t nv = oldv;\n        while (nv == oldv) nv = (uint8_t)rng.nextInt(0, 7);\n        mat[i][j] = nv;\n        vector<CellCh> changes = {{i, j, oldv}};\n        return tryApplyCells(st, changes, T);\n    }\n\n    bool doSegmentOverwriteFromSeq(SAState& st, double T, const vector<uint8_t>& seq, int off, int k) {\n        bool vert = (rng.nextInt(0, 1) == 1);\n        int line = rng.nextInt(0, N - 1);\n        int start = rng.nextInt(0, N - 1);\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n\n        if (!vert) {\n            int r = line;\n            for (int t = 0; t < k; t++) {\n                int c = (start + t) % N;\n                uint8_t nv = seq[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = line;\n            for (int t = 0; t < k; t++) {\n                int r = (start + t) % N;\n                uint8_t nv = seq[off + t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApplyCells(st, changes, T);\n    }\n\n    bool doSegmentOverwriteFromInput(SAState& st, double T, int minK, int maxK) {\n        int idx = rng.nextInt(0, M - 1);\n        const auto& s = inputs[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n        int k = rng.nextInt(minK, min(maxK, L));\n        int off = rng.nextInt(0, L - k);\n        return doSegmentOverwriteFromSeq(st, T, s, off, k);\n    }\n\n    int pickUncoveredIdx(const SAState& st, int samples) {\n        int U = (int)st.occ.size();\n        int best = -1, bestP = -1;\n        for (int t = 0; t < samples; t++) {\n            int idx = rng.nextInt(0, U - 1);\n            if (st.occ[idx] != 0) continue;\n            int p = st.book->impPriority.empty() ? 1 : st.book->impPriority[idx];\n            if (p > bestP) { bestP = p; best = idx; }\n        }\n        return best;\n    }\n\n    bool doImposeUncovered(SAState& st, double T) {\n        if (st.book->pattern.empty()) return false;\n        if (st.score >= st.book->totalWeight) return false;\n\n        int target = pickUncoveredIdx(st, 80);\n        if (target < 0) return false;\n\n        const auto& pat = st.book->pattern[target];\n        int k = (int)pat.size();\n        if (k < 2) return false;\n\n        // choose placement with minimal mismatches\n        bool bestVert = false;\n        int bestLine = 0, bestStart = 0;\n        int bestMismatch = 1e9;\n\n        for (int tt = 0; tt < 90; tt++) {\n            bool vert = (rng.nextInt(0, 1) == 1);\n            int line = rng.nextInt(0, N - 1);\n            int start = rng.nextInt(0, N - 1);\n            int mism = 0;\n            if (!vert) {\n                int r = line;\n                for (int t = 0; t < k; t++) mism += (mat[r][(start + t) % N] != pat[t]);\n            } else {\n                int c = line;\n                for (int t = 0; t < k; t++) mism += (mat[(start + t) % N][c] != pat[t]);\n            }\n            if (mism < bestMismatch) {\n                bestMismatch = mism;\n                bestVert = vert;\n                bestLine = line;\n                bestStart = start;\n                if (bestMismatch == 0) break;\n            }\n        }\n        if (bestMismatch == 0) return false;\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n        if (!bestVert) {\n            int r = bestLine;\n            for (int t = 0; t < k; t++) {\n                int c = (bestStart + t) % N;\n                uint8_t nv = pat[t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        } else {\n            int c = bestLine;\n            for (int t = 0; t < k; t++) {\n                int r = (bestStart + t) % N;\n                uint8_t nv = pat[t];\n                if (mat[r][c] != nv) {\n                    changes.push_back({r, c, mat[r][c]});\n                    mat[r][c] = nv;\n                }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApplyCells(st, changes, T);\n    }\n\n    // directed segment overwrite from an uncovered full string (substring)\n    bool doSegmentFromUncovered(SAState& st, double T, int minK, int maxK) {\n        if (st.book->pattern.empty()) return false;\n        int idx = pickUncoveredIdx(st, 80);\n        if (idx < 0) return false;\n        const auto& s = st.book->pattern[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n        int k = rng.nextInt(minK, min(maxK, L));\n        int off = rng.nextInt(0, L - k);\n        return doSegmentOverwriteFromSeq(st, T, s, off, k);\n    }\n\n    // Anneal window: temperature progress is computed on [phaseStart, phaseEnd], but loop stops at untilTime.\n    void annealWindow(SAState& st,\n                      double phaseStart, double phaseEnd, double untilTime,\n                      double T0, double T1,\n                      double pImpose, double pRotate, double pSeg,\n                      int segMinK, int segMaxK,\n                      bool allowImpose, bool segFromUncoveredInFull) {\n        while (true) {\n            double now = elapsedSec();\n            if (now >= untilTime) break;\n\n            double prog = (now - phaseStart) / max(1e-9, (phaseEnd - phaseStart));\n            prog = min(1.0, max(0.0, prog));\n            double T = T0 * pow(T1 / T0, prog);\n\n            // adaptive impose: more when far from complete\n            double pImp = pImpose;\n            if (allowImpose) {\n                double frac = (double)st.score / max(1.0, (double)st.book->totalWeight);\n                pImp = pImpose + (1.0 - frac) * 0.08;\n                if (pImp > 0.30) pImp = 0.30;\n            }\n\n            double r = rng.nextDouble();\n            if (allowImpose && r < pImp) {\n                doImposeUncovered(st, T);\n            } else if (r < pImp + pRotate) {\n                bool row = (rng.nextInt(0, 1) == 0);\n                int id = rng.nextInt(0, N - 1);\n                int sh = rng.nextInt(1, 3);\n                if (rng.nextInt(0, 1)) sh = N - sh;\n                tryRotate(st, row, id, sh, T);\n            } else if (r < pImp + pRotate + pSeg) {\n                if (segFromUncoveredInFull && allowImpose) {\n                    // try a targeted segment; fallback to random input if not possible\n                    if (!doSegmentFromUncovered(st, T, segMinK, segMaxK)) {\n                        doSegmentOverwriteFromInput(st, T, segMinK, segMaxK);\n                    }\n                } else {\n                    doSegmentOverwriteFromInput(st, T, segMinK, segMaxK);\n                }\n            } else {\n                doCellMutate(st, T);\n            }\n        }\n    }\n\n    void pruneDotsIfAllCovered(const CodeBook& fullBook) {\n        SAState st;\n        st.init(mat, fullBook);\n        if (st.score != fullBook.totalWeight) return;\n\n        vector<int> order(N * N);\n        iota(order.begin(), order.end(), 0);\n        for (int i = (int)order.size() - 1; i > 0; i--) swap(order[i], order[rng.nextInt(0, i)]);\n\n        for (int p : order) {\n            int i = p / N, j = p % N;\n            if (mat[i][j] == DOT) continue;\n\n            uint8_t oldv = mat[i][j];\n            mat[i][j] = DOT;\n\n            int rowLine = i, colLine = 20 + j;\n            long long oldScore = st.score;\n\n            st.computeLineInto(rowLine, st.tmpA);\n            st.replaceSwapLine(rowLine, st.tmpA);\n            st.computeLineInto(colLine, st.tmpB);\n            st.replaceSwapLine(colLine, st.tmpB);\n\n            if (st.score != fullBook.totalWeight) {\n                st.replaceSwapLine(colLine, st.tmpB);\n                st.replaceSwapLine(rowLine, st.tmpA);\n                mat[i][j] = oldv;\n                st.score = oldScore;\n            }\n        }\n    }\n\n    void solveAndPrint() {\n        // Build books: A (k-mers), B (k-mers + boosted full), C (full only)\n        FlatMap wA; wA.reserve((size_t)25000);\n        FlatMap wB; wB.reserve((size_t)35000);\n        FlatMap wC; wC.reserve((size_t)2048);\n\n        auto addSubs = [&](FlatMap& w, const vector<uint8_t>& s, int minLen, int maxLen, int base) {\n            int L = (int)s.size();\n            for (int len = minLen; len <= maxLen; len++) {\n                if (len > L) break;\n                int mul = base * (len * len);\n                for (int st = 0; st + len <= L; st++) w[encodeVec(s, st, len)] += mul;\n            }\n        };\n\n        const int FULL_BOOST = 80;\n\n        for (auto &s : inputs) {\n            wC[encodeFull(s)] += 1;\n            wB[encodeFull(s)] += FULL_BOOST;\n            addSubs(wA, s, 3, 7, 1);\n            addSubs(wB, s, 4, 8, 1);\n        }\n\n        CodeBook bookA = makeCodeBook(wA, 3, 7, false);\n        CodeBook bookB = makeCodeBook(wB, 2, 12, false);\n        CodeBook bookC = makeCodeBook(wC, 2, 12, true);\n\n        startTime = chrono::steady_clock::now();\n        const double TL = 2.88;\n\n        initByFreq();\n\n        SAState st;\n\n        // Time split (empirically stable): give B enough time, then strong C with snapshotting.\n        const double phaseAEnd = 0.85;\n        const double phaseBEnd = 2.30;\n        const double phaseCEnd  = TL - 0.06;      // keep for greedy/prune/output\n        const double fullSAEnd  = phaseCEnd - 0.11;\n\n        // Phase A\n        st.init(mat, bookA);\n        annealWindow(st,\n                     /*phaseStart*/0.0, /*phaseEnd*/phaseAEnd, /*until*/min(phaseAEnd, TL),\n                     /*T0*/4500.0, /*T1*/40.0,\n                     /*pImpose*/0.0, /*pRotate*/0.015, /*pSeg*/0.14,\n                     /*segMinK*/4, /*segMaxK*/9,\n                     /*allowImpose*/false, /*segFromUncoveredInFull*/false);\n\n        // Phase B\n        st.init(mat, bookB);\n        annealWindow(st,\n                     /*phaseStart*/phaseAEnd, /*phaseEnd*/phaseBEnd, /*until*/min(phaseBEnd, TL),\n                     /*T0*/3000.0, /*T1*/15.0,\n                     /*pImpose*/0.0, /*pRotate*/0.020, /*pSeg*/0.18,\n                     /*segMinK*/5, /*segMaxK*/12,\n                     /*allowImpose*/false, /*segFromUncoveredInFull*/false);\n\n        // Phase C (chunked for best snapshot, but with global temp schedule)\n        st.init(mat, bookC);\n        array<array<uint8_t, N>, N> bestMat = mat;\n        long long bestScore = st.score;\n\n        while (elapsedSec() < fullSAEnd) {\n            double segUntil = min(fullSAEnd, elapsedSec() + 0.20);\n            annealWindow(st,\n                         /*phaseStart*/phaseBEnd, /*phaseEnd*/phaseCEnd, /*until*/segUntil,\n                         /*T0*/210.0, /*T1*/0.8,\n                         /*pImpose*/0.16, /*pRotate*/0.020, /*pSeg*/0.10,\n                         /*segMinK*/6, /*segMaxK*/12,\n                         /*allowImpose*/true, /*segFromUncoveredInFull*/true);\n\n            if (st.score > bestScore) {\n                bestScore = st.score;\n                bestMat = mat;\n            }\n        }\n\n        mat = bestMat;\n        st.init(mat, bookC);\n\n        // Greedy finishing: try multiple attempts (don\u2019t stop on first miss)\n        while (elapsedSec() < phaseCEnd - 0.02 && st.score < bookC.totalWeight) {\n            long long before = st.score;\n            // alternate impose and targeted segment\n            if (rng.nextDouble() < 0.65) doImposeUncovered(st, 1e-9);\n            else doSegmentFromUncovered(st, 1e-9, 6, 12);\n            // if no improvement, just continue trying until time runs out\n            (void)before;\n        }\n\n        pruneDotsIfAllCovered(bookC);\n\n        for (int i = 0; i < N; i++) {\n            string out;\n            out.reserve(N);\n            for (int j = 0; j < N; j++) {\n                uint8_t v = mat[i][j];\n                out.push_back(v == DOT ? '.' : char('A' + v));\n            }\n            cout << out << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, M;\n    cin >> n >> M;\n\n    Solver solver(M);\n    solver.inputs.reserve(M);\n    for (int i = 0; i < M; i++) {\n        string s;\n        cin >> s;\n        vector<uint8_t> v;\n        v.reserve(s.size());\n        for (char c : s) v.push_back((uint8_t)(c - 'A')); // A..H -> 0..7\n        solver.inputs.push_back(std::move(v));\n    }\n\n    solver.solveAndPrint();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed=88172645463325252ULL) : x(seed) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    uint64_t operator()() { return next(); }\n    int next_int(int lo, int hi) { return lo + (int)(next() % (uint64_t)(hi - lo + 1)); }\n    double next_double() { // [0,1)\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct TimeKeeper {\n    chrono::steady_clock::time_point st;\n    double limit;\n    TimeKeeper(double limitSec): st(chrono::steady_clock::now()), limit(limitSec) {}\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n    double remaining() const { return limit - elapsed(); }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj;\n    vector<int> dist;\n    vector<int> pairU, pairV;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                int u2 = pairV[v];\n                if(u2 != -1 && dist[u2] == -1){\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n                if(u2 == -1) found = true;\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for(int v: adj[u]){\n            int u2 = pairV[v];\n            if(u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))){\n                pairU[u] = v;\n                pairV[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        pairU.assign(nL, -1);\n        pairV.assign(nR, -1);\n        int matching = 0;\n        while(bfs()){\n            for(int u=0; u<nL; u++){\n                if(pairU[u] == -1 && dfs(u)) matching++;\n            }\n        }\n        return matching;\n    }\n\n    // Konig: min vertex cover after max matching\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                if(pairU[u] == v) continue; // only non-matching edges\n                if(!visR[v]){\n                    visR[v] = 1;\n                    int u2 = pairV[v];\n                    if(u2 != -1 && !visL[u2]){\n                        visL[u2] = 1;\n                        q.push(u2);\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for(int u=0; u<nL; u++) if(!visL[u]) coverL[u] = 1;\n        for(int v=0; v<nR; v++) if(visR[v])  coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct Dinic {\n    struct Edge { int to, rev; long long cap; };\n    int N;\n    vector<vector<Edge>> G;\n    vector<int> level, it;\n\n    Dinic(int n=0){ init(n); }\n    void init(int n){\n        N = n;\n        G.assign(N, {});\n        level.assign(N, 0);\n        it.assign(N, 0);\n    }\n    void add_edge(int fr, int to, long long cap){\n        Edge a{to, (int)G[to].size(), cap};\n        Edge b{fr, (int)G[fr].size(), 0};\n        G[fr].push_back(a);\n        G[to].push_back(b);\n    }\n    bool bfs(int s, int t){\n        fill(level.begin(), level.end(), -1);\n        queue<int> q;\n        level[s] = 0;\n        q.push(s);\n        while(!q.empty()){\n            int v = q.front(); q.pop();\n            for(const auto &e: G[v]){\n                if(e.cap > 0 && level[e.to] < 0){\n                    level[e.to] = level[v] + 1;\n                    q.push(e.to);\n                }\n            }\n        }\n        return level[t] >= 0;\n    }\n    long long dfs(int v, int t, long long f){\n        if(v == t) return f;\n        for(int &i = it[v]; i < (int)G[v].size(); i++){\n            Edge &e = G[v][i];\n            if(e.cap <= 0 || level[e.to] != level[v] + 1) continue;\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if(ret > 0){\n                e.cap -= ret;\n                G[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n        return 0;\n    }\n    long long max_flow(int s, int t){\n        long long flow = 0;\n        while(bfs(s,t)){\n            fill(it.begin(), it.end(), 0);\n            while(true){\n                long long f = dfs(s,t, (1LL<<62));\n                if(!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n    vector<char> mincut_reachable(int s){\n        vector<char> vis(N, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n        while(!q.empty()){\n            int v = q.front(); q.pop();\n            for(const auto &e: G[v]){\n                if(e.cap > 0 && !vis[e.to]){\n                    vis[e.to] = 1;\n                    q.push(e.to);\n                }\n            }\n        }\n        return vis;\n    }\n};\n\nstruct Solver {\n    int N, si, sj;\n    vector<string> c;\n\n    vector<vector<int>> id;\n    vector<int> xs, ys, w;\n    int R = 0;\n\n    vector<int> hseg, vseg;\n    int H = 0, V = 0;\n\n    vector<vector<int>> segAdj; // H -> unique V\n    vector<int> degH, degV;\n\n    // grid neighbors\n    vector<array<int,4>> nbr;\n    vector<uint8_t> deg;\n\n    // visibility\n    int W64 = 0;\n    vector<uint64_t> visFlat, allMask;\n\n    // Dijkstra buffers\n    static constexpr int INF = 1e9;\n    vector<int> dist;\n    vector<int> prevv;\n\n    void read() {\n        cin >> N >> si >> sj;\n        c.resize(N);\n        for(int i=0;i<N;i++) cin >> c[i];\n    }\n\n    void build_nodes() {\n        id.assign(N, vector<int>(N, -1));\n        xs.clear(); ys.clear(); w.clear();\n        R = 0;\n        for(int i=0;i<N;i++){\n            for(int j=0;j<N;j++){\n                if(c[i][j] == '#') continue;\n                id[i][j] = R++;\n                xs.push_back(i);\n                ys.push_back(j);\n                w.push_back(c[i][j]-'0');\n            }\n        }\n        dist.assign(R, INF);\n        prevv.assign(R, -1);\n        hseg.assign(R, -1);\n        vseg.assign(R, -1);\n\n        nbr.assign(R, array<int,4>{-1,-1,-1,-1});\n        deg.assign(R, 0);\n        for(int v=0; v<R; v++){\n            int x=xs[v], y=ys[v];\n            auto add = [&](int nx,int ny){\n                int u = (0<=nx && nx<N && 0<=ny && ny<N) ? id[nx][ny] : -1;\n                if(u!=-1) nbr[v][deg[v]++] = u;\n            };\n            add(x-1,y); add(x+1,y); add(x,y-1); add(x,y+1);\n        }\n    }\n\n    void build_segments() {\n        H = 0;\n        for(int i=0;i<N;i++){\n            int j=0;\n            while(j<N){\n                if(id[i][j] == -1){ j++; continue; }\n                int sid = H++;\n                while(j<N && id[i][j] != -1){\n                    hseg[id[i][j]] = sid;\n                    j++;\n                }\n            }\n        }\n        V = 0;\n        for(int j=0;j<N;j++){\n            int i=0;\n            while(i<N){\n                if(id[i][j] == -1){ i++; continue; }\n                int sid = V++;\n                while(i<N && id[i][j] != -1){\n                    vseg[id[i][j]] = sid;\n                    i++;\n                }\n            }\n        }\n    }\n\n    void build_segment_graph() {\n        segAdj.assign(H, {});\n        for(int node=0; node<R; node++){\n            segAdj[hseg[node]].push_back(vseg[node]);\n        }\n        for(int h=0; h<H; h++){\n            auto &v = segAdj[h];\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n        degH.assign(H, 0);\n        degV.assign(V, 0);\n        for(int h=0; h<H; h++){\n            degH[h] = (int)segAdj[h].size();\n            for(int v: segAdj[h]) degV[v]++;\n        }\n    }\n\n    void build_visibility_bitsets() {\n        W64 = (R + 63) / 64;\n        // visFlat[v] = hseg-bitset OR vseg-bitset, but we can compute directly by scanning row/col segments:\n        // easiest: build per segment bitsets first then OR them; memory ok.\n        vector<uint64_t> hbits((size_t)H * W64, 0ULL);\n        vector<uint64_t> vbits((size_t)V * W64, 0ULL);\n        visFlat.assign((size_t)R * W64, 0ULL);\n\n        for(int v=0; v<R; v++){\n            int hi=hseg[v], vi=vseg[v];\n            int word=v>>6, bit=v&63;\n            hbits[(size_t)hi * W64 + word] |= (1ULL<<bit);\n            vbits[(size_t)vi * W64 + word] |= (1ULL<<bit);\n        }\n        for(int v=0; v<R; v++){\n            uint64_t* dst = &visFlat[(size_t)v * W64];\n            const uint64_t* hb = &hbits[(size_t)hseg[v] * W64];\n            const uint64_t* vb = &vbits[(size_t)vseg[v] * W64];\n            for(int k=0;k<W64;k++) dst[k] = hb[k] | vb[k];\n        }\n\n        allMask.assign(W64, ~0ULL);\n        if(R % 64 != 0) allMask[W64-1] = (1ULL << (R%64)) - 1ULL;\n    }\n\n    template<class Pred>\n    int dijkstra_until(int s, Pred pred) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        using P = pair<int,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            if(pred(v)) return v;\n            for(int k=0;k<deg[v];k++){\n                int to = nbr[v][k];\n                int nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push({nd,to});\n                }\n            }\n        }\n        return -1;\n    }\n\n    void dijkstra_store(int s, int* prevOut, int* distOut) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        using P = pair<int,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n        dist[s] = 0;\n        pq.push({0,s});\n        while(!pq.empty()){\n            auto [d,v] = pq.top(); pq.pop();\n            if(d != dist[v]) continue;\n            for(int k=0;k<deg[v];k++){\n                int to = nbr[v][k];\n                int nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push({nd,to});\n                }\n            }\n        }\n        memcpy(prevOut, prevv.data(), sizeof(int)*R);\n        memcpy(distOut, dist.data(), sizeof(int)*R);\n    }\n\n    pair<vector<char>, vector<char>> compute_min_vertex_cover_card(bool shuffleAdj, XorShift64& rng) {\n        HopcroftKarp hk(H, V);\n        hk.adj = segAdj;\n        if(shuffleAdj){\n            for(int h=0; h<H; h++){\n                auto &v = hk.adj[h];\n                for(int i=(int)v.size()-1;i>0;i--){\n                    int j = (int)(rng() % (uint64_t)(i+1));\n                    swap(v[i], v[j]);\n                }\n            }\n        }\n        hk.max_matching();\n        return hk.min_vertex_cover();\n    }\n\n    // Exact minimum-weight vertex cover in bipartite graph via min s-t cut\n    pair<vector<char>, vector<char>> compute_min_vertex_cover_weighted(const vector<long long>& wH,\n                                                                       const vector<long long>& wV) {\n        const long long INF_CAP = (1LL<<50);\n        int S = H + V;\n        int T = H + V + 1;\n        Dinic din(H + V + 2);\n        for(int h=0; h<H; h++) din.add_edge(S, h, wH[h]);\n        for(int v=0; v<V; v++) din.add_edge(H + v, T, wV[v]);\n        for(int h=0; h<H; h++){\n            for(int v: segAdj[h]){\n                din.add_edge(h, H + v, INF_CAP);\n            }\n        }\n        din.max_flow(S, T);\n        auto reach = din.mincut_reachable(S);\n        // min vertex cover: (H \\ Z) U (V \u2229 Z), where Z = reachable from S in residual\n        vector<char> coverH(H, 0), coverV(V, 0);\n        for(int h=0; h<H; h++) if(!reach[h]) coverH[h] = 1;\n        for(int v=0; v<V; v++) if(reach[H+v]) coverV[v] = 1;\n        return {coverH, coverV};\n    }\n\n    struct Top3 {\n        array<int,3> d;\n        array<int,3> v;\n        Top3(){ d = {INF,INF,INF}; v = {-1,-1,-1}; }\n        void upd(int nd, int nv){\n            for(int k=0;k<3;k++){\n                if(nd < d[k]){\n                    for(int t=2;t>k;t--){ d[t]=d[t-1]; v[t]=v[t-1]; }\n                    d[k]=nd; v[k]=nv;\n                    return;\n                }\n            }\n        }\n        int pick(bool randomPick, XorShift64& rng) const {\n            if(!randomPick) return v[0];\n            int cand[3]; int m=0;\n            for(int k=0;k<3;k++) if(v[k]!=-1) cand[m++] = v[k];\n            if(m==0) return -1;\n            return cand[rng.next_int(0, m-1)];\n        }\n    };\n\n    vector<int> build_waypoints_unpaired(const vector<char>& needH, const vector<char>& needV,\n                                         int startId, const vector<int>& distS,\n                                         bool randomPick, XorShift64& rng) {\n        vector<Top3> bestH(H), bestV(V);\n        for(int node=0; node<R; node++){\n            int h=hseg[node], v=vseg[node];\n            if(needH[h]) bestH[h].upd(distS[node], node);\n            if(needV[v]) bestV[v].upd(distS[node], node);\n        }\n        vector<int> wp;\n        wp.push_back(startId);\n        vector<int> tail;\n        tail.reserve(H+V);\n        for(int h=0; h<H; h++) if(needH[h]) {\n            int node = bestH[h].pick(randomPick, rng);\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n        for(int v=0; v<V; v++) if(needV[v]) {\n            int node = bestV[v].pick(randomPick, rng);\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n        sort(tail.begin(), tail.end());\n        tail.erase(unique(tail.begin(), tail.end()), tail.end());\n        wp.insert(wp.end(), tail.begin(), tail.end());\n        if(wp.size()==1 && R>1 && deg[startId]) wp.push_back(nbr[startId][0]);\n        return wp;\n    }\n\n    vector<int> build_waypoints_paired(const vector<char>& needH, const vector<char>& needV,\n                                       int startId, const vector<int>& distS,\n                                       bool randomPick, XorShift64& rng) {\n        vector<int> mapH(H,-1), mapV(V,-1), reqH, reqV;\n        for(int h=0; h<H; h++) if(needH[h]) { mapH[h]=(int)reqH.size(); reqH.push_back(h); }\n        for(int v=0; v<V; v++) if(needV[v]) { mapV[v]=(int)reqV.size(); reqV.push_back(v); }\n        int Hr=(int)reqH.size(), Vr=(int)reqV.size();\n\n        vector<Top3> bestH(Hr), bestV(Vr);\n\n        struct Rep2 { int d1=INF, n1=-1, d2=INF, n2=-1; };\n        unordered_map<uint64_t, Rep2> rep;\n        rep.reserve((size_t)R * 2);\n\n        auto keyUV = [&](int u, int v)->uint64_t {\n            return (uint64_t)(uint32_t)u<<32 | (uint32_t)v;\n        };\n\n        for(int node=0; node<R; node++){\n            int h=hseg[node], v=vseg[node];\n            int u = mapH[h], vv = mapV[v];\n            if(u!=-1) bestH[u].upd(distS[node], node);\n            if(vv!=-1) bestV[vv].upd(distS[node], node);\n\n            if(u!=-1 && vv!=-1){\n                uint64_t key = keyUV(u,vv);\n                auto &r = rep[key];\n                int d = distS[node];\n                if(d < r.d1){\n                    r.d2=r.d1; r.n2=r.n1;\n                    r.d1=d; r.n1=node;\n                }else if(d < r.d2 && node != r.n1){\n                    r.d2=d; r.n2=node;\n                }\n            }\n        }\n\n        HopcroftKarp hk(Hr, Vr);\n        hk.adj.assign(Hr, {});\n        for(auto &kv : rep){\n            uint64_t key = kv.first;\n            int u = (int)(key >> 32);\n            int vv = (int)(key & 0xffffffffu);\n            hk.adj[u].push_back(vv);\n        }\n        for(int u=0; u<Hr; u++){\n            auto &vec = hk.adj[u];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            if(randomPick && vec.size() >= 2){\n                for(int i=(int)vec.size()-1;i>0;i--){\n                    int j = (int)(rng() % (uint64_t)(i+1));\n                    swap(vec[i], vec[j]);\n                }\n            }\n        }\n\n        hk.max_matching();\n        vector<char> matchedV(Vr, 0);\n\n        vector<int> wp; wp.push_back(startId);\n        vector<int> tail;\n        tail.reserve(Hr+Vr);\n\n        for(int u=0; u<Hr; u++){\n            int vv = hk.pairU[u];\n            if(vv!=-1){\n                matchedV[vv]=1;\n                auto &r = rep[keyUV(u,vv)];\n                int node = r.n1;\n                if(randomPick && r.n2!=-1 && (rng() & 1ULL)) node = r.n2;\n                if(node!=-1 && node!=startId) tail.push_back(node);\n            }else{\n                int node = bestH[u].v[0];\n                if(node!=-1 && node!=startId) tail.push_back(node);\n            }\n        }\n        for(int vv=0; vv<Vr; vv++){\n            if(matchedV[vv]) continue;\n            int node = bestV[vv].v[0];\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n\n        sort(tail.begin(), tail.end());\n        tail.erase(unique(tail.begin(), tail.end()), tail.end());\n        wp.insert(wp.end(), tail.begin(), tail.end());\n        if(wp.size()==1 && R>1 && deg[startId]) wp.push_back(nbr[startId][0]);\n        return wp;\n    }\n\n    // APSP among waypoints with prev trees + flattened D\n    void build_apsp_with_prevs(const vector<int>& wp, vector<int>& Dflat, vector<int>& prevs) {\n        int m = (int)wp.size();\n        Dflat.assign(m*m, INF);\n        prevs.assign((size_t)m * R, -1);\n        vector<int> distRow(R);\n        for(int i=0;i<m;i++){\n            dijkstra_store(wp[i], &prevs[(size_t)i * R], distRow.data());\n            for(int j=0;j<m;j++){\n                Dflat[i*m + j] = distRow[wp[j]];\n            }\n        }\n    }\n\n    inline long long cycle_cost(const vector<int>& seq, const vector<int>& Dflat, int m) const {\n        long long cost=0;\n        for(int i=0;i<m;i++) cost += Dflat[seq[i]*m + seq[(i+1)%m]];\n        return cost;\n    }\n\n    vector<int> init_nearest_neighbor(const vector<int>& Dflat, int m) {\n        vector<int> seq; seq.reserve(m);\n        vector<char> used(m, 0);\n        int cur = 0;\n        seq.push_back(0); used[0]=1;\n        for(int step=1; step<m; step++){\n            int best=-1, bestD=INF;\n            for(int j=1;j<m;j++){\n                if(used[j]) continue;\n                int d = Dflat[cur*m + j];\n                if(d < bestD){ bestD=d; best=j; }\n            }\n            if(best==-1){\n                for(int j=1;j<m;j++) if(!used[j]) { best=j; break; }\n            }\n            used[best]=1;\n            seq.push_back(best);\n            cur = best;\n        }\n        return seq;\n    }\n\n    vector<int> init_cheapest_insertion(const vector<int>& Dflat, int m) {\n        if(m <= 2){\n            vector<int> seq(m);\n            iota(seq.begin(), seq.end(), 0);\n            return seq;\n        }\n        vector<char> used(m, 0);\n        used[0] = 1;\n\n        int best2 = 1;\n        long long bestVal = (long long)Dflat[0*m + 1] + Dflat[1*m + 0];\n        for(int j=2;j<m;j++){\n            long long v = (long long)Dflat[0*m + j] + Dflat[j*m + 0];\n            if(v < bestVal){\n                bestVal = v;\n                best2 = j;\n            }\n        }\n        vector<int> seq = {0, best2};\n        used[best2] = 1;\n\n        for(int cnt=2; cnt<m; cnt++){\n            int bestX=-1, bestPos=-1;\n            long long bestDelta = (1LL<<60);\n            for(int x=1;x<m;x++){\n                if(used[x]) continue;\n                int L = (int)seq.size();\n                for(int pos=0; pos<L; pos++){\n                    int a = seq[pos];\n                    int b = seq[(pos+1)%L];\n                    long long delta = (long long)Dflat[a*m + x] + Dflat[x*m + b] - Dflat[a*m + b];\n                    if(delta < bestDelta){\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            seq.insert(seq.begin() + bestPos + 1, bestX);\n            used[bestX] = 1;\n        }\n        auto it = find(seq.begin(), seq.end(), 0);\n        rotate(seq.begin(), it, seq.end());\n        return seq;\n    }\n\n    // Moves: relocate1, swap, Or-opt(2) (careful overlap)\n    // SA: accept uphill with exp(-delta/temp)\n    void optimize_waypoint_order_sa(vector<int>& seq, const vector<int>& Dflat, int m, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        if(m <= 3) return;\n\n        auto prev_idx = [&](int i){ return (i-1+m)%m; };\n        auto next_idx = [&](int i){ return (i+1)%m; };\n\n        long long curCost = cycle_cost(seq, Dflat, m);\n        vector<int> bestSeq = seq;\n        long long bestCost = curCost;\n\n        const double T0 = 5000.0;\n        const double T1 = 5.0;\n\n        int accepted = 0;\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n            double frac = elapsed / max(1e-9, timeLimitSec);\n            double temp = T0 * pow(T1 / T0, frac);\n\n            int op = (int)(rng() % 3);\n\n            if(op == 0){\n                // relocate1\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = (int)(rng() % (uint64_t)m);\n                if(j==i) continue;\n                if(next_idx(j)==i) continue;\n\n                int pi=prev_idx(i), ni=next_idx(i);\n                int a=seq[pi], x=seq[i], b=seq[ni];\n                int c=seq[j], d=seq[next_idx(j)];\n\n                long long old = (long long)Dflat[a*m + x] + Dflat[x*m + b] + Dflat[c*m + d];\n                long long neu = (long long)Dflat[a*m + b] + Dflat[c*m + x] + Dflat[x*m + d];\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    int xval = seq[i];\n                    if(i < j){\n                        seq.erase(seq.begin()+i);\n                        seq.insert(seq.begin()+j, xval);\n                    }else{\n                        seq.erase(seq.begin()+i);\n                        seq.insert(seq.begin()+j+1, xval);\n                    }\n                    // keep 0 at front\n                    if(seq[0] != 0){\n                        auto it = find(seq.begin(), seq.end(), 0);\n                        rotate(seq.begin(), it, seq.end());\n                    }\n                    curCost += delta;\n                    accepted++;\n                }\n            }else if(op == 1){\n                // swap\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = 1 + (int)(rng() % (uint64_t)(m-1));\n                if(i==j) continue;\n                if(i>j) swap(i,j);\n\n                int pi=prev_idx(i), ni=next_idx(i);\n                int pj=prev_idx(j), nj=next_idx(j);\n\n                int a=seq[pi], b=seq[i], c=seq[ni];\n                int d=seq[pj], e=seq[j], f=seq[nj];\n\n                long long old, neu;\n                if(ni == j){\n                    old = (long long)Dflat[a*m + b] + Dflat[b*m + e] + Dflat[e*m + f];\n                    neu = (long long)Dflat[a*m + e] + Dflat[e*m + b] + Dflat[b*m + f];\n                }else{\n                    old = (long long)Dflat[a*m + b] + Dflat[b*m + c] + Dflat[d*m + e] + Dflat[e*m + f];\n                    neu = (long long)Dflat[a*m + e] + Dflat[e*m + c] + Dflat[d*m + b] + Dflat[b*m + f];\n                }\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                    accepted++;\n                }\n            }else{\n                // Or-opt(2): move block (i,i+1), i in [1..m-2]\n                if(m < 5) continue;\n                int i = 1 + (int)(rng() % (uint64_t)(m-2));\n                int i2 = i + 1;\n                int j = (int)(rng() % (uint64_t)m);\n                if(j==i || j==i2) continue;\n\n                int pi = i-1;\n                int ni = (i2+1)%m;\n                int jn = (j+1)%m;\n\n                // avoid overlapping/adjacent ambiguous cases\n                if(j == pi) continue;\n                if(jn == i || jn == i2) continue;\n\n                int P = seq[pi];\n                int A = seq[i];\n                int B = seq[i2];\n                int Nn = seq[ni];\n                int J = seq[j];\n                int JN = seq[jn];\n\n                long long old = (long long)Dflat[P*m + A] + Dflat[B*m + Nn] + Dflat[J*m + JN];\n                long long neu = (long long)Dflat[P*m + Nn] + Dflat[J*m + A] + Dflat[B*m + JN];\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    int Aval=A, Bval=B;\n                    seq.erase(seq.begin()+i2);\n                    seq.erase(seq.begin()+i);\n                    int jj = j;\n                    if(j > i2) jj -= 2;\n                    int pos = jj + 1;\n                    if(pos > (int)seq.size()) pos = (int)seq.size();\n                    seq.insert(seq.begin()+pos, Aval);\n                    seq.insert(seq.begin()+pos+1, Bval);\n\n                    if(seq[0] != 0){\n                        auto it = find(seq.begin(), seq.end(), 0);\n                        rotate(seq.begin(), it, seq.end());\n                    }\n                    curCost += delta;\n                    accepted++;\n                }\n            }\n\n            // Correct drift occasionally (and update best)\n            if((accepted & 31) == 0){\n                curCost = cycle_cost(seq, Dflat, m);\n            }\n            if(curCost < bestCost){\n                bestCost = curCost;\n                bestSeq = seq;\n            }\n        }\n        seq.swap(bestSeq);\n    }\n\n    vector<int> expand_route_from_seq(const vector<int>& wp, const vector<int>& seq, const vector<int>& prevs) {\n        int m = (int)wp.size();\n        vector<int> route;\n        route.push_back(wp[seq[0]]);\n\n        auto restore = [&](int srcIdx, int srcNode, int dstNode){\n            const int* prv = &prevs[(size_t)srcIdx * R];\n            int cur = dstNode;\n            vector<int> tmp;\n            tmp.push_back(cur);\n            while(cur != srcNode && cur != -1){\n                cur = prv[cur];\n                tmp.push_back(cur);\n            }\n            if(tmp.back() != srcNode) return;\n            reverse(tmp.begin(), tmp.end());\n            for(size_t k=1;k<tmp.size();k++) route.push_back(tmp[k]);\n        };\n\n        for(int i=0;i<m;i++){\n            int a = seq[i];\n            int b = seq[(i+1)%m];\n            restore(a, wp[a], wp[b]);\n        }\n        return route;\n    }\n\n    pair<bool,long long> eval_full_visibility(const vector<int>& route) const {\n        vector<uint64_t> cov(W64, 0ULL);\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            const uint64_t* vb = &visFlat[(size_t)v * W64];\n            for(int k=0;k<W64;k++) cov[k] |= vb[k];\n        }\n        for(int k=0;k<W64;k++){\n            if(cov[k] != allMask[k]) return {false, t};\n        }\n        return {true, t};\n    }\n\n    vector<int> improve_by_shortcuts_full_fast(vector<int> route, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_full_visibility(route);\n        if(!ok0) return route;\n\n        auto rebuild_aux = [&](const vector<int>& r,\n                               vector<long long>& preTime,\n                               vector<uint64_t>& pref,\n                               vector<uint64_t>& suf,\n                               long long& totalT){\n            int L=(int)r.size();\n            preTime.assign(L, 0LL);\n            totalT = 0;\n            for(int i=1;i<L;i++){\n                totalT += w[r[i]];\n                preTime[i] = totalT;\n            }\n            pref.assign((size_t)L * W64, 0ULL);\n            suf.assign((size_t)(L+1) * W64, 0ULL);\n\n            for(int i=0;i<L;i++){\n                const uint64_t* vb = &visFlat[(size_t)r[i] * W64];\n                uint64_t* dst = &pref[(size_t)i * W64];\n                if(i==0){\n                    for(int k=0;k<W64;k++) dst[k] = vb[k];\n                }else{\n                    uint64_t* prv = &pref[(size_t)(i-1) * W64];\n                    for(int k=0;k<W64;k++) dst[k] = prv[k] | vb[k];\n                }\n            }\n            for(int i=L-1;i>=0;i--){\n                const uint64_t* vb = &visFlat[(size_t)r[i] * W64];\n                uint64_t* dst = &suf[(size_t)i * W64];\n                uint64_t* nxt = &suf[(size_t)(i+1) * W64];\n                for(int k=0;k<W64;k++) dst[k] = nxt[k] | vb[k];\n            }\n        };\n\n        vector<long long> preTime;\n        vector<uint64_t> pref, suf;\n        long long totalT=0;\n        rebuild_aux(route, preTime, pref, suf, totalT);\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L=(int)route.size();\n            if(L < 12) continue;\n\n            int len = 5 + (int)(rng() % 260);\n            if(len >= L) len = L-1;\n            int a = (int)(rng() % (uint64_t)(L - len));\n            int b = a + len;\n            if(a >= b) continue;\n\n            int sNode = route[a];\n            int tNode = route[b];\n\n            long long oldCost = preTime[b] - preTime[a];\n\n            int reached = dijkstra_until(sNode, [&](int v){ return v==tNode; });\n            if(reached != tNode) continue;\n            long long newCost = dist[tNode];\n            if(newCost >= oldCost) continue;\n\n            vector<int> path;\n            int cur = tNode;\n            while(cur != -1){\n                path.push_back(cur);\n                if(cur == sNode) break;\n                cur = prevv[cur];\n            }\n            reverse(path.begin(), path.end());\n            if(path.empty() || path.front()!=sNode) continue;\n\n            vector<uint64_t> mid(W64, 0ULL);\n            for(int v: path){\n                const uint64_t* vb = &visFlat[(size_t)v * W64];\n                for(int k=0;k<W64;k++) mid[k] |= vb[k];\n            }\n\n            bool ok = true;\n            for(int k=0;k<W64;k++){\n                uint64_t left  = (a>0) ? pref[(size_t)(a-1)*W64 + k] : 0ULL;\n                uint64_t right = (b+1<L) ? suf[(size_t)(b+1)*W64 + k] : 0ULL;\n                if((left | mid[k] | right) != allMask[k]) { ok=false; break; }\n            }\n            if(!ok) continue;\n\n            long long candT = totalT - oldCost + newCost;\n            if(candT <= 0 || candT >= bestT) continue;\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin()+a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin()+b+1, route.end());\n\n            route.swap(nr);\n            bestT = candT;\n            rebuild_aux(route, preTime, pref, suf, totalT);\n        }\n        return route;\n    }\n\n    string route_to_moves(const vector<int>& route) const {\n        string out;\n        out.reserve(route.size() ? route.size()-1 : 0);\n        for(size_t i=1;i<route.size();i++){\n            int a=route[i-1], b=route[i];\n            int x1=xs[a], y1=ys[a], x2=xs[b], y2=ys[b];\n            if(x2==x1-1 && y2==y1) out.push_back('U');\n            else if(x2==x1+1 && y2==y1) out.push_back('D');\n            else if(x2==x1 && y2==y1-1) out.push_back('L');\n            else if(x2==x1 && y2==y1+1) out.push_back('R');\n        }\n        return out;\n    }\n\n    void solve() {\n        read();\n        build_nodes();\n        build_segments();\n        build_segment_graph();\n        build_visibility_bitsets();\n\n        int startId = id[si][sj];\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n        TimeKeeper tk(2.95);\n\n        // dist from start\n        vector<int> distS(R, INF), prevTmp(R, -1);\n        dijkstra_store(startId, prevTmp.data(), distS.data());\n\n        // segment min distance\n        vector<int> segMinH(H, INF), segMinV(V, INF);\n        for(int node=0; node<R; node++){\n            segMinH[hseg[node]] = min(segMinH[hseg[node]], distS[node]);\n            segMinV[vseg[node]] = min(segMinV[vseg[node]], distS[node]);\n        }\n\n        // --- generate diverse covers ---\n        vector<pair<vector<char>, vector<char>>> covers;\n        // min-card covers\n        covers.push_back(compute_min_vertex_cover_card(false, rng));\n        for(int i=0;i<7;i++) covers.push_back(compute_min_vertex_cover_card(true, rng));\n\n        // min-weight covers with different weight schemes\n        auto make_weight_cover = [&](int scheme, int noiseAmp)->pair<vector<char>, vector<char>>{\n            vector<long long> wH(H), wV(V);\n            for(int h=0; h<H; h++){\n                long long base = (long long)segMinH[h] + 1;\n                if(scheme == 1) base = base - 20LL * degH[h];       // favor high degree\n                if(scheme == 2) base = base + 20LL * degH[h];       // disfavor high degree\n                long long noise = (noiseAmp ? rng.next_int(0, noiseAmp) : 0);\n                wH[h] = max(1LL, base + noise);\n            }\n            for(int v=0; v<V; v++){\n                long long base = (long long)segMinV[v] + 1;\n                if(scheme == 1) base = base - 20LL * degV[v];\n                if(scheme == 2) base = base + 20LL * degV[v];\n                long long noise = (noiseAmp ? rng.next_int(0, noiseAmp) : 0);\n                wV[v] = max(1LL, base + noise);\n            }\n            return compute_min_vertex_cover_weighted(wH, wV);\n        };\n        covers.push_back(make_weight_cover(0, 400));\n        covers.push_back(make_weight_cover(1, 600));\n        covers.push_back(make_weight_cover(2, 600));\n\n        // --- build waypoint plans + cheap preselection ---\n        struct Plan { long long est; vector<int> wp; };\n        vector<Plan> plans;\n        plans.reserve(covers.size() * 4);\n\n        auto add_plan = [&](vector<char> needH, vector<char> needV, int mode){\n            // remove free segments (start belongs to both its segments)\n            needH[hseg[startId]] = 0;\n            needV[vseg[startId]] = 0;\n\n            // safety if empty\n            int cntNeed=0;\n            for(char x: needH) cntNeed += (x!=0);\n            for(char x: needV) cntNeed += (x!=0);\n            if(cntNeed==0){\n                needH.assign(H, 1);\n                needV.assign(V, 0);\n                needH[hseg[startId]] = 0;\n            }\n\n            vector<int> wp;\n            if(mode == 0) wp = build_waypoints_unpaired(needH, needV, startId, distS, false, rng);\n            else if(mode == 1) wp = build_waypoints_unpaired(needH, needV, startId, distS, true, rng);\n            else if(mode == 2) wp = build_waypoints_paired(needH, needV, startId, distS, false, rng);\n            else wp = build_waypoints_paired(needH, needV, startId, distS, true, rng);\n\n            if((int)wp.size() <= 1) return;\n            if((int)wp.size() > 90) return; // avoid expensive APSP\n\n            long long sumD = 0;\n            int mx = 0;\n            for(size_t i=1;i<wp.size();i++){\n                sumD += distS[wp[i]];\n                mx = max(mx, distS[wp[i]]);\n            }\n            long long alpha = 520; // tuned: waypoint penalty\n            long long est = alpha * (long long)wp.size() + sumD + 2LL * mx;\n            plans.push_back({est, std::move(wp)});\n        };\n\n        for(auto &cv : covers){\n            if(tk.remaining() < 1.8) break;\n            add_plan(cv.first, cv.second, 0);\n            add_plan(cv.first, cv.second, 2);\n            add_plan(cv.first, cv.second, 1);\n            add_plan(cv.first, cv.second, 3);\n        }\n\n        sort(plans.begin(), plans.end(), [&](const Plan& a, const Plan& b){ return a.est < b.est; });\n        int planKeep = min<int>(22, (int)plans.size());\n        plans.resize(planKeep);\n\n        // --- evaluate plans with APSP + tour optimization, keep only best few candidates (memory-safe) ---\n        struct Cand {\n            long long cycleCost;\n            vector<int> wp;\n            vector<int> seq;\n            vector<int> prevs;\n            vector<int> Dflat;\n            int m;\n        };\n        vector<Cand> cands;\n        int candKeep = 10;\n\n        for(int pi=0; pi<planKeep; pi++){\n            if(tk.remaining() < 1.0) break;\n            auto &wp = plans[pi].wp;\n            int m = (int)wp.size();\n            if(m <= 1) continue;\n\n            vector<int> Dflat, prevs;\n            build_apsp_with_prevs(wp, Dflat, prevs);\n\n            vector<int> s1 = init_nearest_neighbor(Dflat, m);\n            vector<int> s2 = init_cheapest_insertion(Dflat, m);\n\n            // quick greedy optimization\n            optimize_waypoint_order_sa(s1, Dflat, m, 0.02, rng);\n            optimize_waypoint_order_sa(s2, Dflat, m, 0.02, rng);\n\n            long long c1 = cycle_cost(s1, Dflat, m);\n            long long c2 = cycle_cost(s2, Dflat, m);\n\n            vector<int> bestSeq = (c2 < c1) ? std::move(s2) : std::move(s1);\n            long long bestC = min(c1, c2);\n\n            cands.push_back(Cand{bestC, wp, std::move(bestSeq), std::move(prevs), std::move(Dflat), m});\n            // keep only best candKeep by cycleCost\n            if((int)cands.size() > candKeep){\n                auto it = max_element(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                    return a.cycleCost < b.cycleCost;\n                });\n                cands.erase(it);\n            }\n        }\n\n        if(cands.empty()){\n            vector<int> route = {startId};\n            if(R > 1 && deg[startId]){\n                int nb = nbr[startId][0];\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n            cout << route_to_moves(route) << \"\\n\";\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){ return a.cycleCost < b.cycleCost; });\n\n        // --- top-K candidates: stronger SA + quick shortcut, choose best by actual time ---\n        int K = min<int>(3, (int)cands.size());\n        vector<int> bestRoute;\n        long long bestT = (1LL<<60);\n\n        double quickTotal = min(1.1, max(0.25, tk.remaining() * 0.40));\n        double per = quickTotal / K;\n\n        for(int i=0;i<K;i++){\n            auto cand = std::move(cands[i]); // local copy/move (we may modify seq)\n            // extra SA on waypoint order\n            double saTime = min(0.10, max(0.03, per * 0.35));\n            optimize_waypoint_order_sa(cand.seq, cand.Dflat, cand.m, saTime, rng);\n\n            vector<int> route = expand_route_from_seq(cand.wp, cand.seq, cand.prevs);\n            if(route.size()==1 && R>1 && deg[startId]){\n                int nb = nbr[startId][0];\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n\n            // quick shortcut improvement\n            double cutTime = max(0.01, per - saTime);\n            route = improve_by_shortcuts_full_fast(std::move(route), cutTime, rng);\n\n            auto [ok, t] = eval_full_visibility(route);\n            if(ok && t < bestT){\n                bestT = t;\n                bestRoute.swap(route);\n            }\n        }\n\n        // final shortcut with remaining time\n        double rem = tk.remaining();\n        if(rem > 0.02){\n            bestRoute = improve_by_shortcuts_full_fast(std::move(bestRoute), rem, rng);\n        }\n\n        if(bestRoute.size()==1 && R>1 && deg[startId]){\n            int nb = nbr[startId][0];\n            bestRoute.push_back(nb);\n            bestRoute.push_back(startId);\n        }\n\n        cout << route_to_moves(bestRoute) << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver s;\n    s.solve();\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    if (x < lo) return lo;\n    if (x > hi) return hi;\n    return x;\n}\n\nstruct Item {\n    long long key;\n    int id;\n};\nstruct ItemCmp {\n    bool operator()(const Item& a, const Item& b) const {\n        return a.key < b.key; // max-heap\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    cin >> N >> M >> K >> R;\n\n    vector<vector<int>> d(N, vector<int>(K));\n    for (int i = 0; i < N; i++) for (int k = 0; k < K; k++) cin >> d[i][k];\n\n    vector<vector<int>> g(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        g[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    // Critical path length (task-count based); u<v allows reverse index DP\n    vector<int> cp(N, 1);\n    for (int i = N - 1; i >= 0; i--) {\n        int best = 1;\n        for (int v : g[i]) best = max(best, 1 + cp[v]);\n        cp[i] = best;\n    }\n\n    // Difficulty proxy\n    vector<int> diff(N, 0);\n    for (int i = 0; i < N; i++) {\n        int s = 0;\n        for (int k = 0; k < K; k++) s += d[i][k];\n        diff[i] = s;\n    }\n\n    // Static key for PQ selection\n    vector<long long> key(N);\n    for (int i = 0; i < N; i++) {\n        key[i] = (long long)cp[i] * 1'000'000LL\n               + (long long)diff[i] * 1'000LL\n               + (long long)outdeg[i] * 10LL\n               - (long long)i;\n    }\n\n    // task state: 0 not started, 1 running, 2 done\n    vector<int> state(N, 0);\n\n    // ready management\n    vector<char> in_ready(N, 0);\n    vector<int> ready_since(N, 0);\n\n    priority_queue<Item, vector<Item>, ItemCmp> pq_key;\n    priority_queue<Item, vector<Item>, ItemCmp> pq_age; // key = -ready_since to pop oldest first\n\n    auto push_ready = [&](int task, int day_ready) {\n        if (state[task] != 0) return;\n        if (indeg[task] != 0) return;\n        if (in_ready[task]) return;\n        in_ready[task] = 1;\n        ready_since[task] = day_ready;\n        pq_key.push({key[task], task});\n        pq_age.push({-(long long)day_ready, task});\n    };\n\n    for (int i = 0; i < N; i++) if (indeg[i] == 0) push_ready(i, 0);\n\n    // member state\n    vector<int> member_task(M, -1);\n    vector<int> member_start(M, -1);\n\n    // skill estimates\n    const double SKILL_INIT = 10.0;\n    const double SKILL_MIN = 0.0;\n    const double SKILL_MAX = 80.0;\n    vector<vector<double>> shat(M, vector<double>(K, SKILL_INIT));\n    vector<int> samples(M, 0);\n\n    auto predict_w = [&](int task, int mem) -> double {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double def = (double)d[task][k] - shat[mem][k];\n            if (def > 0) w += def;\n        }\n        return w;\n    };\n\n    // Keep the stable predictor (slightly risk-aware but mild)\n    auto predict_time = [&](int task, int mem) -> double {\n        double w = predict_w(task, mem);\n        double uncert = (1.5 + 0.01 * w) / sqrt(1.0 + samples[mem]); // mild dependence on task hardness\n        double bias = 0.6;\n        return max(1.0, w + bias + uncert);\n    };\n\n    // Interval-based update (noise-aware) from the good previous version\n    auto update_skill_interval = [&](int mem, int task, int t_obs) {\n        double lo, hi;\n        if (t_obs <= 1) {\n            lo = 0.0;\n            hi = 4.0; // t==1 can happen even when w>0 due to negative noise\n        } else {\n            lo = max(1.0, (double)t_obs - 3.0);\n            hi = (double)t_obs + 3.0;\n        }\n\n        vector<double> def(K);\n        vector<int> active;\n        active.reserve(K);\n        double w_hat = 0.0;\n        for (int k = 0; k < K; k++) {\n            def[k] = max(0.0, (double)d[task][k] - shat[mem][k]);\n            if (def[k] > 1e-12) active.push_back(k);\n            w_hat += def[k];\n        }\n\n        if (lo - 1e-9 <= w_hat && w_hat <= hi + 1e-9) return;\n\n        double lr = 0.8 / sqrt(1.0 + samples[mem]);\n\n        if (w_hat > hi) {\n            if (active.empty()) return;\n            double need = w_hat - hi;\n            double step = lr * need;\n            for (int k : active) {\n                double frac = def[k] / w_hat;\n                double inc = step * frac;\n                inc = min(inc, def[k]);\n                shat[mem][k] = clampd(shat[mem][k] + inc, SKILL_MIN, SKILL_MAX);\n            }\n        } else { // w_hat < lo\n            double need = lo - w_hat;\n            double step = lr * need;\n\n            if (!active.empty()) {\n                double denom = 0.0;\n                for (int k : active) denom += (def[k] + 1.0);\n                for (int k : active) {\n                    double frac = (def[k] + 1.0) / denom;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            } else {\n                double denom = 1e-9;\n                for (int k = 0; k < K; k++) denom += (double)d[task][k] + 1.0;\n                for (int k = 0; k < K; k++) {\n                    double frac = ((double)d[task][k] + 1.0) / denom;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }\n        }\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    const int CKEY = 180;\n    const int CAGE = 80;\n\n    for (int day = 1; day <= 2000; day++) {\n        // free members\n        vector<int> free_m;\n        free_m.reserve(M);\n        for (int j = 0; j < M; j++) if (member_task[j] == -1) free_m.push_back(j);\n        shuffle(free_m.begin(), free_m.end(), rng);\n\n        // build candidate tasks from PQs\n        vector<int> cand;\n        cand.reserve(CKEY + CAGE);\n\n        vector<pair<long long,int>> popped_key;\n        vector<pair<long long,int>> popped_age;\n        popped_key.reserve(CKEY * 2);\n        popped_age.reserve(CAGE * 2);\n\n        vector<char> usedC(N, 0);\n\n        auto take_from = [&](auto &pq, int limit, vector<pair<long long,int>> &popped) {\n            while (!pq.empty() && (int)cand.size() < limit) {\n                auto it = pq.top(); pq.pop();\n                popped.push_back({it.key, it.id});\n                int t = it.id;\n                if (state[t] != 0 || indeg[t] != 0 || !in_ready[t]) continue;\n                if (usedC[t]) continue;\n                usedC[t] = 1;\n                cand.push_back(t);\n            }\n        };\n\n        take_from(pq_key, CKEY, popped_key);\n        take_from(pq_age, CKEY + CAGE, popped_age);\n\n        vector<pair<int,int>> assigns;\n\n        if (!free_m.empty() && !cand.empty()) {\n            int F = (int)free_m.size();\n            int Tn = (int)cand.size();\n            int flow_need = min(F, Tn);\n\n            // per-task statistics among free members (for safer matching)\n            vector<double> avg_pt(Tn, 1.0), best_pt(Tn, 1.0);\n            for (int j = 0; j < Tn; j++) {\n                double sum = 0.0;\n                double best = 1e100;\n                for (int mem : free_m) {\n                    double pt = predict_time(cand[j], mem);\n                    sum += pt;\n                    best = min(best, pt);\n                }\n                avg_pt[j] = sum / (double)F;\n                best_pt[j] = best;\n            }\n\n            auto weight_pair = [&](int mem, int task, int tidx) -> double {\n                double pt = predict_time(task, mem);\n                double pr = (double)cp[task]\n                          + 0.03 * (double)outdeg[task]\n                          + 0.001 * (double)diff[task];\n\n                // age bonus ramps slightly later to flush tail\n                double age = (double)(day - ready_since[task]);\n                double age_coef = (day < 1200 ? 0.0008 : 0.00115);\n                double age_bonus = age_coef * age;\n\n                double explore = 0.02 / sqrt(1.0 + samples[mem]);\n                double adv = 0.10 * ((avg_pt[tidx] - pt) / (avg_pt[tidx] + 1e-9));\n\n                // anti-catastrophe: penalize being much worse than best for that task\n                double badfit = max(0.0, (pt - best_pt[tidx]) / (best_pt[tidx] + 1e-9));\n                double badfit_pen = 0.22 * badfit;\n\n                double len_pen = 0.00055 * pt;\n\n                return pr / pow(max(1.0, pt), 0.85) + age_bonus + explore + adv - badfit_pen - len_pen;\n            };\n\n            // compute max weight for non-negative costs\n            vector<vector<double>> W(F, vector<double>(Tn, 0.0));\n            double maxW = -1e100;\n            for (int i = 0; i < F; i++) {\n                int mem = free_m[i];\n                for (int j = 0; j < Tn; j++) {\n                    double w = weight_pair(mem, cand[j], j);\n                    W[i][j] = w;\n                    if (w > maxW) maxW = w;\n                }\n            }\n            if (!(maxW > -1e50)) maxW = 0.0;\n\n            const double SCALE = 1e6;\n\n            int S = 0;\n            int mem0 = 1;\n            int task0 = mem0 + F;\n            int TT = task0 + Tn;\n\n            atcoder::mcf_graph<int, long long> mcf(TT + 1);\n            for (int i = 0; i < F; i++) mcf.add_edge(S, mem0 + i, 1, 0);\n            for (int j = 0; j < Tn; j++) mcf.add_edge(task0 + j, TT, 1, 0);\n\n            struct Rec { int eid; int mem; int task; };\n            vector<Rec> rec;\n            rec.reserve(F * Tn);\n\n            for (int i = 0; i < F; i++) {\n                int mem = free_m[i];\n                for (int j = 0; j < Tn; j++) {\n                    double c = (maxW - W[i][j]) * SCALE;\n                    long long cost = (long long)llround(c);\n                    if (cost < 0) cost = 0; // FP rounding guard\n                    int eid = mcf.add_edge(mem0 + i, task0 + j, 1, cost);\n                    rec.push_back({eid, mem, cand[j]});\n                }\n            }\n\n            mcf.flow(S, TT, flow_need);\n            auto edges = mcf.edges();\n            for (auto &e : rec) {\n                if (edges[e.eid].flow == 1) assigns.push_back({e.mem, e.task});\n            }\n\n            for (auto [mem, task] : assigns) {\n                state[task] = 1;\n                in_ready[task] = 0;\n                member_task[mem] = task;\n                member_start[mem] = day;\n            }\n        }\n\n        // re-push popped entries that remain ready and unassigned\n        vector<char> assigned_today(N, 0);\n        for (auto [m, t] : assigns) assigned_today[t] = 1;\n\n        for (auto &e : popped_key) {\n            int t = e.second;\n            if (state[t] == 0 && indeg[t] == 0 && in_ready[t] && !assigned_today[t]) {\n                pq_key.push({e.first, t});\n            }\n        }\n        for (auto &e : popped_age) {\n            int t = e.second;\n            if (state[t] == 0 && indeg[t] == 0 && in_ready[t] && !assigned_today[t]) {\n                pq_age.push({e.first, t});\n            }\n        }\n\n        // Output assignments\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) {\n            cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        }\n        cout << '\\n' << flush;\n\n        // Input: finished members\n        int nfin;\n        cin >> nfin;\n        if (nfin == -1) return 0;\n\n        for (int i = 0; i < nfin; i++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = member_task[f];\n            int st = member_start[f];\n            int t_obs = day - st + 1;\n\n            update_skill_interval(f, task, t_obs);\n            samples[f]++;\n\n            member_task[f] = -1;\n            member_start[f] = -1;\n\n            state[task] = 2;\n            for (int v : g[task]) {\n                indeg[v]--;\n                if (indeg[v] == 0 && state[v] == 0) {\n                    // becomes ready after end of this day, startable next day\n                    push_ready(v, day);\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Order { int ax, ay, cx, cy; };\nstruct Point { int x, y; };\nstatic inline int distMan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\nstatic const Point OFFICE{400, 400};\n\nstruct Node {\n    int id;\n    uint8_t tp; // 0 pickup, 1 delivery\n};\n\nstruct RNG {\n    uint64_t s;\n    explicit RNG(uint64_t seed) : s(seed) {}\n    static inline uint64_t splitmix64(uint64_t &x) {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    inline uint64_t next_u64() { return splitmix64(s); }\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct BestState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    int cost = INT_MAX;\n};\n\nstruct CurState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    array<Point,102> pts{}; // OFFICE + 100 nodes + OFFICE\n    int cost = INT_MAX;\n\n    array<int,1000> pickPos;\n    array<int,1000> delPos;\n    array<uint8_t,1000> selected;\n};\n\nstatic inline Point nodePoint(const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              const Node& nd) {\n    return (nd.tp == 0 ? pickPt[nd.id] : delPt[nd.id]);\n}\n\nstatic inline int computeCostFromPts(const array<Point,102>& pts) {\n    int c = 0;\n    for (int i = 0; i < 101; i++) c += distMan(pts[i], pts[i+1]);\n    return c;\n}\n\nstatic void buildPtsAndPos(CurState& st,\n                           const array<Point,1000>& pickPt,\n                           const array<Point,1000>& delPt) {\n    st.pts[0] = OFFICE;\n    for (int i = 0; i < 100; i++) st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[101] = OFFICE;\n    st.cost = computeCostFromPts(st.pts);\n\n    st.pickPos.fill(-1);\n    st.delPos.fill(-1);\n    for (int i = 0; i < 100; i++) {\n        const Node &nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n}\n\nstatic array<Node,100> buildGreedyInterleaving(const array<Point,1000>& pickPt,\n                                               const array<Point,1000>& delPt,\n                                               const array<int,50>& sel) {\n    vector<int> unpicked; unpicked.reserve(50);\n    for (int i = 0; i < 50; i++) unpicked.push_back(sel[i]);\n    vector<int> carrying; carrying.reserve(50);\n\n    array<Node,100> seq;\n    Point cur = OFFICE;\n\n    auto erase_by_swap_back = [](vector<int>& v, int idx) {\n        v[idx] = v.back();\n        v.pop_back();\n    };\n\n    for (int t = 0; t < 100; t++) {\n        int bestDist = INT_MAX, bestId = -1, bestType = -1, bestIdx = -1;\n\n        for (int i = 0; i < (int)unpicked.size(); i++) {\n            int id = unpicked[i];\n            int d = distMan(cur, pickPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 0; bestIdx = i; }\n        }\n        for (int i = 0; i < (int)carrying.size(); i++) {\n            int id = carrying[i];\n            int d = distMan(cur, delPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 1; bestIdx = i; }\n        }\n\n        if (bestType == 0) {\n            seq[t] = Node{bestId, 0};\n            cur = pickPt[bestId];\n            carrying.push_back(bestId);\n            erase_by_swap_back(unpicked, bestIdx);\n        } else {\n            seq[t] = Node{bestId, 1};\n            cur = delPt[bestId];\n            erase_by_swap_back(carrying, bestIdx);\n        }\n    }\n    return seq;\n}\n\n// Best insertion of pickup+delivery into base sequence (size L), pickup before delivery.\nstatic pair<vector<Node>, int> bestInsertPairFast(const vector<Node>& base,\n                                                  const Point& pick,\n                                                  const Point& del,\n                                                  int idToInsert,\n                                                  const array<Point,1000>& pickPt,\n                                                  const array<Point,1000>& delPt) {\n    const int L = (int)base.size();\n\n    vector<Point> pts(L + 2);\n    pts[0] = OFFICE;\n    for (int i = 0; i < L; i++) pts[i+1] = nodePoint(pickPt, delPt, base[i]);\n    pts[L+1] = OFFICE;\n\n    int baseCost = 0;\n    for (int i = 0; i < L+1; i++) baseCost += distMan(pts[i], pts[i+1]);\n\n    int bestDelta = INT_MAX;\n    int bestP = 0;\n    int bestD = 1;\n\n    for (int p = 0; p <= L; p++) {\n        int delta1 = distMan(pts[p], pick) + distMan(pick, pts[p+1]) - distMan(pts[p], pts[p+1]);\n\n        for (int dpos = p+1; dpos <= L+1; dpos++) {\n            Point left, right;\n            if (dpos == p+1) {\n                left = pick;\n                right = pts[p+1];\n            } else {\n                left = pts[dpos-1];\n                right = pts[dpos];\n            }\n            int delta2 = distMan(left, del) + distMan(del, right) - distMan(left, right);\n            int tot = delta1 + delta2;\n            if (tot < bestDelta) {\n                bestDelta = tot;\n                bestP = p;\n                bestD = dpos;\n            }\n        }\n    }\n\n    vector<Node> res = base;\n    res.insert(res.begin() + bestP, Node{idToInsert, 0});\n    res.insert(res.begin() + bestD, Node{idToInsert, 1});\n    int newCost = baseCost + bestDelta;\n    return {res, newCost};\n}\n\nstatic pair<array<Node,100>, int> buildCheapestInsertionRoute(const array<int,50>& sel,\n                                                              vector<int> orderIds,\n                                                              const array<Point,1000>& pickPt,\n                                                              const array<Point,1000>& delPt) {\n    vector<Node> nodes;\n    nodes.reserve(100);\n    int cost = 0;\n    for (int id : orderIds) {\n        auto [nn, nc] = bestInsertPairFast(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n        nodes = move(nn);\n        cost = nc;\n    }\n    array<Node,100> seq;\n    for (int i = 0; i < 100; i++) seq[i] = nodes[i];\n    return {seq, cost};\n}\n\nstatic inline void applyRelocate(array<Node,100>& a, int i, int j) {\n    if (i == j) return;\n    Node tmp = a[i];\n    if (i < j) {\n        for (int k = i; k < j; k++) a[k] = a[k+1];\n        a[j] = tmp;\n    } else {\n        for (int k = i; k > j; k--) a[k] = a[k-1];\n        a[j] = tmp;\n    }\n}\n\nstatic inline int deltaSwapPts(const array<Point,102>& pts, int i, int j) {\n    int a = i + 1, b = j + 1;\n    auto getPt = [&](int idx)->Point {\n        if (idx == a) return pts[b];\n        if (idx == b) return pts[a];\n        return pts[idx];\n    };\n\n    int edges[4] = {a-1, a, b-1, b};\n    sort(edges, edges+4);\n    int oldc = 0, newc = 0;\n    int last = -999;\n    for (int k = 0; k < 4; k++) {\n        int e = edges[k];\n        if (e == last) continue;\n        last = e;\n        if (0 <= e && e <= 100) {\n            oldc += distMan(pts[e], pts[e+1]);\n            newc += distMan(getPt(e), getPt(e+1));\n        }\n    }\n    return newc - oldc;\n}\n\nstatic inline int deltaRelocatePts(const array<Point,102>& pts, int i, int j) {\n    const Point& X = pts[i+1];\n    const Point& A = pts[i];\n    const Point& B = pts[i+2];\n    int delta_rem = distMan(A, B) - distMan(A, X) - distMan(X, B);\n\n    Point C, D;\n    if (i < j) { C = pts[j+1]; D = pts[j+2]; }\n    else { C = pts[j]; D = pts[j+1]; }\n    int delta_ins = distMan(C, X) + distMan(X, D) - distMan(C, D);\n    return delta_rem + delta_ins;\n}\n\nstatic inline bool canRelocateOrderConstraint(const CurState& st, int i, int j) {\n    const Node& nd = st.seq[i];\n    int id = nd.id;\n    int p = st.pickPos[id];\n    int d = st.delPos[id];\n    int other = (nd.tp == 0 ? d : p);\n\n    int new_other = other;\n    if (i < j) {\n        if (other >= i + 1 && other <= j) new_other = other - 1;\n    } else {\n        if (other >= j && other <= i - 1) new_other = other + 1;\n    }\n\n    if (nd.tp == 0) return j < new_other;\n    else return new_other < j;\n}\n\nstatic inline bool canSwapOrderConstraint(const CurState& st, int i, int j) {\n    const Node& a = st.seq[i];\n    const Node& b = st.seq[j];\n    if (a.id == b.id) return false;\n\n    {\n        int id = a.id;\n        int np = (a.tp == 0 ? j : st.pickPos[id]);\n        int nd = (a.tp == 1 ? j : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    {\n        int id = b.id;\n        int np = (b.tp == 0 ? i : st.pickPos[id]);\n        int nd = (b.tp == 1 ? i : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    return true;\n}\n\nstatic void updateRangeAfterRelocate(CurState& st,\n                                     const array<Point,1000>& pickPt,\n                                     const array<Point,1000>& delPt,\n                                     int l, int r) {\n    for (int k = l; k <= r; k++) {\n        st.pts[k+1] = nodePoint(pickPt, delPt, st.seq[k]);\n        const Node& nd = st.seq[k];\n        if (nd.tp == 0) st.pickPos[nd.id] = k;\n        else st.delPos[nd.id] = k;\n    }\n}\n\nstatic void updateAfterSwap(CurState& st,\n                            const array<Point,1000>& pickPt,\n                            const array<Point,1000>& delPt,\n                            int i, int j) {\n    st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[j+1] = nodePoint(pickPt, delPt, st.seq[j]);\n    {\n        const Node& nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n    {\n        const Node& nd = st.seq[j];\n        if (nd.tp == 0) st.pickPos[nd.id] = j;\n        else st.delPos[nd.id] = j;\n    }\n}\n\nstatic vector<Node> baseWithoutPositions(const array<Node,100>& seq, const vector<int>& posToSkip) {\n    array<uint8_t,100> skip{};\n    skip.fill(0);\n    for (int p : posToSkip) skip[p] = 1;\n    vector<Node> base;\n    base.reserve(100 - (int)posToSkip.size());\n    for (int i = 0; i < 100; i++) if (!skip[i]) base.push_back(seq[i]);\n    return base;\n}\n\nstatic void greedyImproveRelocate(CurState& st,\n                                  const array<Point,1000>& pickPt,\n                                  const array<Point,1000>& delPt,\n                                  RNG& rng,\n                                  int iters) {\n    for (int it = 0; it < iters; it++) {\n        int i = rng.next_int(0, 99);\n        int j = rng.next_int(0, 99);\n        if (i == j) continue;\n        if (!canRelocateOrderConstraint(st, i, j)) continue;\n\n        int delta = deltaRelocatePts(st.pts, i, j);\n        if (delta >= 0) continue;\n\n        applyRelocate(st.seq, i, j);\n        int l = min(i, j), r = max(i, j);\n        updateRangeAfterRelocate(st, pickPt, delPt, l, r);\n        st.cost += delta;\n    }\n}\n\nstatic void hillClimbOrderReinsert(CurState& st,\n                                   const array<Point,1000>& pickPt,\n                                   const array<Point,1000>& delPt,\n                                   RNG& rng,\n                                   int attempts) {\n    for (int t = 0; t < attempts; t++) {\n        int idx = rng.next_int(0, 49);\n        int id = st.sel[idx];\n        int pi = st.pickPos[id], di = st.delPos[id];\n        if (!(0 <= pi && pi < di && di < 100)) continue;\n\n        vector<Node> base = baseWithoutPositions(st.seq, {pi, di});\n        auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[id], delPt[id], id, pickPt, delPt);\n        if (newCost < st.cost) {\n            for (int i = 0; i < 100; i++) st.seq[i] = newNodes[i];\n            buildPtsAndPos(st, pickPt, delPt);\n        }\n    }\n}\n\n// \"badness\" per selected order: incident edges around pickup+delivery nodes\nstatic inline int orderIncidentCost(const CurState& st, int id) {\n    int p = st.pickPos[id], d = st.delPos[id];\n    if (!(0 <= p && p < d && d < 100)) return INT_MAX/4;\n    auto edgeSumAtPos = [&](int pos)->int {\n        int idx = pos + 1;\n        return distMan(st.pts[idx-1], st.pts[idx]) + distMan(st.pts[idx], st.pts[idx+1]);\n    };\n    return edgeSumAtPos(p) + edgeSumAtPos(d);\n}\n\nstatic vector<int> pickKOutIndices(const CurState& st, RNG& rng, int k) {\n    vector<pair<int,int>> v;\n    v.reserve(50);\n    for (int i = 0; i < 50; i++) {\n        int id = st.sel[i];\n        v.push_back({orderIncidentCost(st, id), i});\n    }\n    sort(v.begin(), v.end(), greater<>());\n    int cand = min(24, (int)v.size());\n    vector<int> out; out.reserve(k);\n    array<uint8_t,50> used{}; used.fill(0);\n    while ((int)out.size() < k) {\n        int idx = rng.next_int(0, cand-1);\n        int si = v[idx].second;\n        if (!used[si]) { used[si] = 1; out.push_back(si); }\n    }\n    return out;\n}\n\nstatic Point routeMedianCenter(const CurState& st) {\n    // Use median of visited points (100 points); Manhattan-friendly.\n    static array<int,100> xs, ys;\n    for (int i = 0; i < 100; i++) {\n        xs[i] = st.pts[i+1].x;\n        ys[i] = st.pts[i+1].y;\n    }\n    nth_element(xs.begin(), xs.begin() + 50, xs.end());\n    nth_element(ys.begin(), ys.begin() + 50, ys.end());\n    return Point{xs[50], ys[50]};\n}\n\n// CDF-biased sampling from pool with forbidden mask\nstatic int sampleFromPoolCDF(const vector<int>& pool, const vector<double>& cdf,\n                             const array<uint8_t,1000>& forbidden, RNG& rng, int tries=200) {\n    double sum = cdf.back();\n    for (int t = 0; t < tries; t++) {\n        double r = rng.next_double() * sum;\n        int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n        idx = max(0, min(idx, (int)pool.size() - 1));\n        int id = pool[idx];\n        if (!forbidden[id]) return id;\n    }\n    return -1;\n}\n\nstatic int sampleFromPoolCDFNear(const vector<int>& pool, const vector<double>& cdf,\n                                 const array<uint8_t,1000>& forbidden, RNG& rng,\n                                 const Point& center, int radius,\n                                 const array<Point,1000>& pickPt, const array<Point,1000>& delPt,\n                                 int tries=260) {\n    double sum = cdf.back();\n    for (int t = 0; t < tries; t++) {\n        double r = rng.next_double() * sum;\n        int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n        idx = max(0, min(idx, (int)pool.size() - 1));\n        int id = pool[idx];\n        if (forbidden[id]) continue;\n        int dp = distMan(center, pickPt[id]);\n        int dd = distMan(center, delPt[id]);\n        if (max(dp, dd) <= radius) return id;\n    }\n    return -1;\n}\n\nstatic array<int,50> sampleSelBiased(const vector<int>& pool, RNG& rng, const vector<double>& cdf) {\n    array<int,50> sel;\n    array<uint8_t,1000> used{}; used.fill(0);\n    for (int k = 0; k < 50; k++) {\n        int id = sampleFromPoolCDF(pool, cdf, used, rng);\n        if (id < 0) { // fallback\n            do { id = pool[rng.next_int(0, (int)pool.size()-1)]; } while (used[id]);\n        }\n        used[id] = 1;\n        sel[k] = id;\n    }\n    return sel;\n}\n\nstatic array<int,50> sampleSelCluster(const array<Point,1000>& pickPt,\n                                      const array<Point,1000>& delPt,\n                                      RNG& rng,\n                                      const Point& center) {\n    vector<pair<int,int>> v;\n    v.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int cp = distMan(center, pickPt[i]);\n        int cd = distMan(center, delPt[i]);\n        int pd = distMan(pickPt[i], delPt[i]);\n        int op = distMan(OFFICE, pickPt[i]);\n        int od = distMan(OFFICE, delPt[i]);\n        int score = (cp + cd) * 100 + pd * 28 + (op + od) * 10;\n        v.push_back({score, i});\n    }\n    nth_element(v.begin(), v.begin() + 50, v.end());\n    v.resize(50);\n    array<int,50> sel;\n    for (int i = 0; i < 50; i++) sel[i] = v[i].second;\n    return sel;\n}\n\nstatic CurState buildStateFromSelTryConstructors(const array<int,50>& sel,\n                                                const array<Point,1000>& pickPt,\n                                                const array<Point,1000>& delPt,\n                                                RNG& rng) {\n    CurState st;\n    st.sel = sel;\n    st.selected.fill(0);\n    for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n\n    array<Node,100> bestSeq = buildGreedyInterleaving(pickPt, delPt, st.sel);\n\n    CurState tmp;\n    tmp.sel = st.sel; tmp.seq = bestSeq; tmp.selected = st.selected;\n    buildPtsAndPos(tmp, pickPt, delPt);\n    int bestCost = tmp.cost;\n\n    // cheapest insertion far-first\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            int da = distMan(OFFICE, pickPt[a]) + distMan(OFFICE, delPt[a]);\n            int db = distMan(OFFICE, pickPt[b]) + distMan(OFFICE, delPt[b]);\n            return da > db;\n        });\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n    // cheapest insertion random\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        shuffle(ids.begin(), ids.end(), std::mt19937((uint32_t)rng.next_u64()));\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n\n    st.seq = bestSeq;\n    buildPtsAndPos(st, pickPt, delPt);\n    return st;\n}\n\nstatic pair<vector<Node>, int> insertSequence(const vector<Node>& base,\n                                              const vector<int>& ids,\n                                              const array<Point,1000>& pickPt,\n                                              const array<Point,1000>& delPt) {\n    vector<Node> nodes = base;\n    int cost = INT_MAX;\n    for (int id : ids) {\n        auto res = bestInsertPairFast(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n        nodes = move(res.first);\n        cost = res.second;\n    }\n    return {nodes, cost};\n}\n\nstatic pair<vector<Node>, int> bestPermutationInsertK(const vector<Node>& base,\n                                                      vector<int> ids,\n                                                      const array<Point,1000>& pickPt,\n                                                      const array<Point,1000>& delPt) {\n    sort(ids.begin(), ids.end());\n    vector<Node> bestNodes;\n    int bestCost = INT_MAX;\n    do {\n        auto [nodes, cost] = insertSequence(base, ids, pickPt, delPt);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestNodes = move(nodes);\n        }\n    } while (next_permutation(ids.begin(), ids.end()));\n    return {bestNodes, bestCost};\n}\n\nstatic bool moveRouteLNSk(CurState& cur,\n                          const array<Point,1000>& pickPt,\n                          const array<Point,1000>& delPt,\n                          RNG& rng,\n                          int k,\n                          double temp) {\n    auto outIdx = pickKOutIndices(cur, rng, k);\n    vector<int> outIds; outIds.reserve(k);\n    vector<int> skipPos; skipPos.reserve(2*k);\n\n    for (int t = 0; t < k; t++) {\n        int si = outIdx[t];\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 2*k) return false;\n\n    vector<Node> base = baseWithoutPositions(cur.seq, skipPos);\n    auto [bestNodes, newCost] = bestPermutationInsertK(base, outIds, pickPt, delPt);\n\n    int delta = newCost - cur.cost;\n    bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n    if (!accept) return false;\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = bestNodes[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    return true;\n}\n\nstatic bool moveSelectionLNS3(CurState& cur,\n                              const vector<int>& pool,\n                              const vector<double>& cdf,\n                              const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              RNG& rng,\n                              double temp) {\n    auto outIdx = pickKOutIndices(cur, rng, 3);\n    vector<int> outIds; outIds.reserve(3);\n    vector<int> skipPos; skipPos.reserve(6);\n\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 6) return false;\n\n    Point center = routeMedianCenter(cur);\n\n    array<uint8_t,1000> forbidden = cur.selected;\n    vector<int> inIds; inIds.reserve(3);\n\n    // one \"explore\" candidate (no near constraint), then 2 \"coherent\" candidates (near center)\n    int id0 = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n    if (id0 < 0) return false;\n    forbidden[id0] = 1;\n    inIds.push_back(id0);\n\n    for (int t = 0; t < 2; t++) {\n        int id = -1;\n        if (rng.next_double() < 0.75) {\n            id = sampleFromPoolCDFNear(pool, cdf, forbidden, rng, center, 360, pickPt, delPt);\n        }\n        if (id < 0) id = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n        if (id < 0) return false;\n        forbidden[id] = 1;\n        inIds.push_back(id);\n    }\n\n    vector<Node> base = baseWithoutPositions(cur.seq, skipPos);\n    auto [bestNodes, newCost] = bestPermutationInsertK(base, inIds, pickPt, delPt);\n\n    int delta = newCost - cur.cost;\n    bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n    if (!accept) return false;\n\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int outId = outIds[t];\n        int inId = inIds[t];\n        cur.selected[outId] = 0;\n        cur.selected[inId] = 1;\n        cur.sel[si] = inId;\n    }\n    for (int i = 0; i < 100; i++) cur.seq[i] = bestNodes[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    return true;\n}\n\nstatic bool tryImproveRouteLNSk(CurState& st,\n                                const array<Point,1000>& pickPt,\n                                const array<Point,1000>& delPt,\n                                RNG& rng,\n                                int k,\n                                int tries) {\n    bool improved = false;\n    for (int t = 0; t < tries; t++) {\n        CurState bak = st;\n        if (!moveRouteLNSk(st, pickPt, delPt, rng, k, /*temp*/1e-9)) { st = bak; continue; }\n        if (st.cost < bak.cost) improved = true;\n        else st = bak;\n    }\n    return improved;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> ord(1000);\n    for (int i = 0; i < 1000; i++) cin >> ord[i].ax >> ord[i].ay >> ord[i].cx >> ord[i].cy;\n\n    array<Point,1000> pickPt, delPt;\n    for (int i = 0; i < 1000; i++) {\n        pickPt[i] = Point{ord[i].ax, ord[i].ay};\n        delPt[i]  = Point{ord[i].cx, ord[i].cy};\n    }\n\n    // Deterministic seed from input hash\n    uint64_t h = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) { h ^= v; h *= 1099511628211ULL; };\n    for (int i = 0; i < 1000; i++) {\n        mix((uint64_t)ord[i].ax); mix((uint64_t)ord[i].ay);\n        mix((uint64_t)ord[i].cx); mix((uint64_t)ord[i].cy);\n    }\n    RNG rng(h ^ 0x9e3779b97f4a7c15ULL);\n\n    vector<pair<int,int>> solo;\n    solo.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int c = distMan(OFFICE, pickPt[i]) + distMan(pickPt[i], delPt[i]) + distMan(delPt[i], OFFICE);\n        solo.push_back({c, i});\n    }\n    sort(solo.begin(), solo.end());\n\n    int POOL = 940;\n    vector<int> pool; pool.reserve(POOL);\n    for (int i = 0; i < min(POOL, 1000); i++) pool.push_back(solo[i].second);\n\n    const double alpha = 1.13;\n    vector<double> cdf(pool.size());\n    double acc = 0.0;\n    for (int i = 0; i < (int)pool.size(); i++) {\n        double w = 1.0 / pow((double)(i + 1), alpha);\n        acc += w;\n        cdf[i] = acc;\n    }\n\n    auto t0 = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - t0).count();\n    };\n\n    const double INIT_LIMIT = 0.27;\n    const double SA_LIMIT   = 1.92;\n    const double DEADLINE   = 1.985;\n\n    // Initialization\n    BestState initBest;\n    {\n        array<int,50> sel0;\n        for (int i = 0; i < 50; i++) sel0[i] = solo[i].second;\n        CurState st = buildStateFromSelTryConstructors(sel0, pickPt, delPt, rng);\n        greedyImproveRelocate(st, pickPt, delPt, rng, 2000);\n        hillClimbOrderReinsert(st, pickPt, delPt, rng, 16);\n        initBest.cost = st.cost;\n        initBest.sel = st.sel;\n        initBest.seq = st.seq;\n\n        int restarts = 0;\n        while (elapsedSec() < INIT_LIMIT && restarts < 16) {\n            array<int,50> sel;\n            if (restarts < 10) {\n                sel = sampleSelBiased(pool, rng, cdf);\n            } else {\n                int baseId = rng.next_int(0, 999);\n                Point center = (rng.next_int(0, 1) ? pickPt[baseId] : delPt[baseId]);\n                if (rng.next_double() < 0.40) {\n                    Point corner{ (rng.next_int(0,1)?0:800), (rng.next_int(0,1)?0:800) };\n                    center.x = (center.x + corner.x) / 2;\n                    center.y = (center.y + corner.y) / 2;\n                }\n                sel = sampleSelCluster(pickPt, delPt, rng, center);\n            }\n\n            CurState st2 = buildStateFromSelTryConstructors(sel, pickPt, delPt, rng);\n            greedyImproveRelocate(st2, pickPt, delPt, rng, 1400);\n            hillClimbOrderReinsert(st2, pickPt, delPt, rng, 16);\n\n            if (st2.cost < initBest.cost) {\n                initBest.cost = st2.cost;\n                initBest.sel = st2.sel;\n                initBest.seq = st2.seq;\n            }\n            restarts++;\n        }\n    }\n\n    CurState cur;\n    cur.sel = initBest.sel;\n    cur.seq = initBest.seq;\n    cur.selected.fill(0);\n    for (int i = 0; i < 50; i++) cur.selected[cur.sel[i]] = 1;\n    buildPtsAndPos(cur, pickPt, delPt);\n\n    BestState best;\n    best.cost = cur.cost;\n    best.sel = cur.sel;\n    best.seq = cur.seq;\n\n    // SA temperature schedule\n    const double T0 = 3000.0;\n    const double T1 = 12.0;\n\n    while (elapsedSec() < SA_LIMIT) {\n        double e = elapsedSec();\n        double prog = e / SA_LIMIT;\n        double temp = T0 * pow(T1 / T0, prog);\n\n        double r = rng.next_double();\n\n        if (r < 0.48) {\n            // relocate node\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (!canRelocateOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaRelocatePts(cur.pts, i, j);\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            applyRelocate(cur.seq, i, j);\n            int l = min(i, j), rr = max(i, j);\n            updateRangeAfterRelocate(cur, pickPt, delPt, l, rr);\n            cur.cost += delta;\n\n        } else if (r < 0.62) {\n            // swap nodes\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (i > j) swap(i, j);\n            if (!canSwapOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaSwapPts(cur.pts, i, j);\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            swap(cur.seq[i], cur.seq[j]);\n            swap(cur.pts[i+1], cur.pts[j+1]);\n            updateAfterSwap(cur, pickPt, delPt, i, j);\n            cur.cost += delta;\n\n        } else if (r < 0.74) {\n            // single order reinsert\n            int idx = rng.next_int(0, 49);\n            int id = cur.sel[idx];\n            int pi = cur.pickPos[id], di = cur.delPos[id];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            vector<Node> base = baseWithoutPositions(cur.seq, {pi, di});\n            auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[id], delPt[id], id, pickPt, delPt);\n\n            int delta = newCost - cur.cost;\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n\n        } else if (r < 0.84) {\n            // route LNS3\n            if (elapsedSec() < SA_LIMIT - 0.06) moveRouteLNSk(cur, pickPt, delPt, rng, 3, temp);\n\n        } else if (r < 0.88) {\n            // route LNS4 (rare but strong)\n            if (elapsedSec() < SA_LIMIT - 0.10) moveRouteLNSk(cur, pickPt, delPt, rng, 4, temp);\n\n        } else if (r < 0.95) {\n            // single selection swap (sometimes near median center)\n            int outIdx = rng.next_int(0, 49);\n            int outId = cur.sel[outIdx];\n\n            array<uint8_t,1000> forbidden = cur.selected;\n            int inId = -1;\n            if (rng.next_double() < 0.70) {\n                Point center = routeMedianCenter(cur);\n                inId = sampleFromPoolCDFNear(pool, cdf, forbidden, rng, center, 340, pickPt, delPt);\n            }\n            if (inId < 0) inId = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n            if (inId < 0) continue;\n\n            int pi = cur.pickPos[outId], di = cur.delPos[outId];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            vector<Node> base = baseWithoutPositions(cur.seq, {pi, di});\n            auto [newNodes, newCost] = bestInsertPairFast(base, pickPt[inId], delPt[inId], inId, pickPt, delPt);\n\n            int delta = newCost - cur.cost;\n            bool accept = (delta <= 0) || (rng.next_double() < exp(-(double)delta / temp));\n            if (!accept) continue;\n\n            cur.selected[outId] = 0;\n            cur.selected[inId] = 1;\n            cur.sel[outIdx] = inId;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newNodes[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n            greedyImproveRelocate(cur, pickPt, delPt, rng, 200);\n\n        } else {\n            // selection LNS3\n            if (elapsedSec() < SA_LIMIT - 0.10) {\n                moveSelectionLNS3(cur, pool, cdf, pickPt, delPt, rng, temp);\n            }\n        }\n\n        if (cur.cost < best.cost) {\n            best.cost = cur.cost;\n            best.sel = cur.sel;\n            best.seq = cur.seq;\n        }\n    }\n\n    // Final polish (improvement-only)\n    {\n        CurState st;\n        st.sel = best.sel;\n        st.seq = best.seq;\n        st.selected.fill(0);\n        for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n        buildPtsAndPos(st, pickPt, delPt);\n\n        // a few strong improvements\n        tryImproveRouteLNSk(st, pickPt, delPt, rng, 3, 4);\n        if (elapsedSec() < DEADLINE - 0.05) tryImproveRouteLNSk(st, pickPt, delPt, rng, 4, 2);\n\n        while (elapsedSec() < DEADLINE) {\n            int before = st.cost;\n            hillClimbOrderReinsert(st, pickPt, delPt, rng, 22);\n            greedyImproveRelocate(st, pickPt, delPt, rng, 900);\n            if (st.cost < best.cost) {\n                best.cost = st.cost;\n                best.sel = st.sel;\n                best.seq = st.seq;\n            }\n            if (st.cost >= before) break;\n        }\n    }\n\n    // Output\n    cout << 50;\n    for (int i = 0; i < 50; i++) cout << \" \" << (best.sel[i] + 1);\n    cout << \"\\n\";\n\n    vector<Point> path;\n    path.reserve(102);\n    path.push_back(OFFICE);\n    for (int i = 0; i < 100; i++) path.push_back(nodePoint(pickPt, delPt, best.seq[i]));\n    path.push_back(OFFICE);\n\n    vector<Point> comp;\n    comp.reserve(path.size());\n    for (auto &p : path) {\n        if (comp.empty() || comp.back().x != p.x || comp.back().y != p.y) comp.push_back(p);\n    }\n\n    cout << (int)comp.size();\n    for (auto &p : comp) cout << \" \" << p.x << \" \" << p.y;\n    cout << \"\\n\";\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <atcoder/all>\n\nusing namespace std;\nusing atcoder::dsu;\n\nstatic inline int rounded_dist(int x1,int y1,int x2,int y2){\n    long long dx = x1 - x2;\n    long long dy = y1 - y2;\n    double dist = std::sqrt((double)dx*dx + (double)dy*dy);\n    return (int)llround(dist);\n}\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// DSU for contracted components\nstruct DSUFast {\n    int n;\n    vector<int> p, sz;\n    DSUFast(int n=0){ init(n); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int a){\n        while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; }\n        return a;\n    }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a;\n        sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// HLD for max on path (edge value stored at child node position)\nint op_max(int a,int b){ return max(a,b); }\nint e_max(){ return 0; }\n\nstruct HLD {\n    int n;\n    vector<int> parent, depth, heavy, head, pos, sz;\n    vector<int> parEdgeD;\n    vector<int> parEdgeIdx;\n    int cur;\n\n    void build_from_tree(const vector<vector<tuple<int,int,int>>>& tree, int root=0) {\n        n = (int)tree.size();\n        parent.assign(n, -1);\n        depth.assign(n, 0);\n        heavy.assign(n, -1);\n        head.assign(n, 0);\n        pos.assign(n, 0);\n        sz.assign(n, 0);\n        parEdgeD.assign(n, 0);\n        parEdgeIdx.assign(n, -1);\n\n        vector<int> st = {root};\n        vector<int> order;\n        order.reserve(n);\n        while(!st.empty()){\n            int v = st.back(); st.pop_back();\n            order.push_back(v);\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v]) continue;\n                parent[to] = v;\n                depth[to] = depth[v] + 1;\n                parEdgeD[to] = d;\n                parEdgeIdx[to] = idx;\n                st.push_back(to);\n            }\n        }\n\n        for(int i=(int)order.size()-1;i>=0;--i){\n            int v = order[i];\n            sz[v] = 1;\n            int best=-1, bestSz=0;\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v]) continue;\n                sz[v] += sz[to];\n                if(sz[to] > bestSz){\n                    bestSz = sz[to];\n                    best = to;\n                }\n            }\n            heavy[v] = best;\n        }\n\n        cur = 0;\n        function<void(int,int)> decomp = [&](int v,int h){\n            head[v] = h;\n            pos[v] = cur++;\n            if(heavy[v] != -1) decomp(heavy[v], h);\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v] || to == heavy[v]) continue;\n                decomp(to, to);\n            }\n        };\n        decomp(root, root);\n    }\n\n    template<class Seg>\n    int query_max(int a, int b, Seg &seg) const {\n        int res = 0;\n        int u=a, v=b;\n        while(head[u] != head[v]){\n            if(depth[head[u]] < depth[head[v]]) swap(u,v);\n            res = max(res, seg.prod(pos[head[u]], pos[u] + 1));\n            u = parent[head[u]];\n        }\n        if(depth[u] > depth[v]) swap(u,v);\n        res = max(res, seg.prod(pos[u] + 1, pos[v] + 1)); // exclude LCA node position\n        return res;\n    }\n};\n\nstatic inline double clamp13(double x){\n    if(x < 1.0) return 1.0;\n    if(x > 3.0) return 3.0;\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 400;\n    const int M = 1995;\n\n    vector<int> x(N), y(N);\n    for(int i=0;i<N;i++){\n        if(!(cin >> x[i] >> y[i])) return 0;\n    }\n    vector<int> U(M), V(M);\n    for(int i=0;i<M;i++) cin >> U[i] >> V[i];\n\n    vector<int> D(M);\n    for(int i=0;i<M;i++){\n        D[i] = rounded_dist(x[U[i]], y[U[i]], x[V[i]], y[V[i]]);\n        if(D[i] <= 0) D[i] = 1;\n    }\n\n    // Build K guide MSTs on D with deterministic tie-break variations\n    const int K = 5;\n    vector<HLD> hld(K);\n    vector<atcoder::segtree<int, op_max, e_max>> segs;\n    segs.reserve(K);\n    vector<vector<int>> idxToChild(K, vector<int>(M, -1));\n    vector<int> membershipCnt(M, 0);\n    vector<char> inMST0(M, false); // primary guide MST (k=0)\n\n    for(int k=0;k<K;k++){\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a,int b){\n            if(D[a] != D[b]) return D[a] < D[b];\n            if(k==0){\n                if(U[a] != U[b]) return U[a] < U[b];\n                if(V[a] != V[b]) return V[a] < V[b];\n                return a < b;\n            }else{\n                uint64_t ha = splitmix64((uint64_t)a ^ (uint64_t)k * 0x9e3779b97f4a7c15ULL);\n                uint64_t hb = splitmix64((uint64_t)b ^ (uint64_t)k * 0x9e3779b97f4a7c15ULL);\n                if(ha != hb) return ha < hb;\n                return a < b;\n            }\n        });\n\n        dsu uf(N);\n        vector<vector<tuple<int,int,int>>> tree(N); // to, d, idx\n        int picked=0;\n        for(int idx: ord){\n            if(picked == N-1) break;\n            int u=U[idx], v=V[idx];\n            if(uf.same(u,v)) continue;\n            uf.merge(u,v);\n            picked++;\n            tree[u].push_back({v, D[idx], idx});\n            tree[v].push_back({u, D[idx], idx});\n            membershipCnt[idx]++;\n            if(k==0) inMST0[idx] = true;\n        }\n\n        hld[k].build_from_tree(tree, 0);\n\n        for(int v=1; v<N; v++){\n            int idx = hld[k].parEdgeIdx[v];\n            if(idx >= 0) idxToChild[k][idx] = v;\n        }\n\n        vector<int> init(N, 0);\n        for(int v=1; v<N; v++){\n            init[hld[k].pos[v]] = hld[k].parEdgeD[v];\n        }\n        segs.emplace_back(init);\n    }\n\n    // Online DSU: adopted edges are always a forest\n    dsu ufAcc(N);\n    int comps = N;\n\n    vector<int> leaderV(N), idOfLeader(N, -1);\n\n    for(int i=0;i<M;i++){\n        int l;\n        if(!(cin >> l)) break;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        if(comps == 1 || ufAcc.same(u,v)){\n            ans = 0;\n        } else {\n            // Build component ids\n            fill(idOfLeader.begin(), idOfLeader.end(), -1);\n            int C = 0;\n            for(int vv=0; vv<N; vv++){\n                leaderV[vv] = ufAcc.leader(vv);\n                int &id = idOfLeader[leaderV[vv]];\n                if(id == -1) id = C++;\n            }\n            int cu = idOfLeader[leaderV[u]];\n            int cv = idOfLeader[leaderV[v]];\n\n            // Suffix scan: connectivity possibility + local alternatives for cu/cv\n            DSUFast tmp(C);\n            int cc = C;\n\n            const int INF = 1e9;\n            int bestBetween = INF, cntBetween = 0;\n            int bestOutCu = INF, bestOutCv = INF;\n            int cntOutCu = 0, cntOutCv = 0;\n\n            for(int j=i+1;j<M;j++){\n                int a = idOfLeader[ leaderV[U[j]] ];\n                int b = idOfLeader[ leaderV[V[j]] ];\n                if(a==b) continue;\n\n                // connectivity\n                if(tmp.unite(a,b)){\n                    cc--;\n                }\n\n                // local alternative stats (by D only)\n                if((a==cu && b==cv) || (a==cv && b==cu)){\n                    cntBetween++;\n                    bestBetween = min(bestBetween, D[j]);\n                }\n                if(a==cu || b==cu){\n                    cntOutCu++;\n                    bestOutCu = min(bestOutCu, D[j]);\n                }\n                if(a==cv || b==cv){\n                    cntOutCv++;\n                    bestOutCv = min(bestOutCv, D[j]);\n                }\n            }\n\n            bool okReject = (cc == 1);\n            bool take = false;\n\n            if(!okReject){\n                take = true; // forced\n            } else {\n                double t = (double)i / (double)(M-1);\n                double remain = max(1, (M-1-i));\n                double need = comps - 1;\n                double urg = min(1.0, need / remain);\n\n                // slightly stronger near the end\n                double mult = 1.0 + 0.95 * pow(urg, 1.15);\n\n                double cheapK    = clamp13((1.35 + 0.35*t) * mult);\n                double replK     = clamp13((1.75 + 0.35*t) * mult);\n                double treeK     = clamp13((2.10 + 0.30*t) * mult);\n                double replSelfK = clamp13((1.55 + 0.30*t) * mult);\n\n                // membership-based bias (K=5)\n                int mc = membershipCnt[i]; // 0..5\n                if(mc >= 4){\n                    cheapK    = clamp13(cheapK + 0.07);\n                    treeK     = clamp13(treeK  + 0.07);\n                    replSelfK = clamp13(replSelfK + 0.07);\n                } else if(mc == 3){\n                    cheapK    = clamp13(cheapK + 0.05);\n                    treeK     = clamp13(treeK  + 0.06);\n                    replSelfK = clamp13(replSelfK + 0.05);\n                } else if(mc == 2){\n                    cheapK    = clamp13(cheapK + 0.03);\n                    treeK     = clamp13(treeK  + 0.04);\n                    replSelfK = clamp13(replSelfK + 0.03);\n                } else if(mc == 1){\n                    cheapK    = clamp13(cheapK + 0.01);\n                } else { // mc==0\n                    replK     = clamp13(replK - 0.06);\n                    replSelfK = clamp13(replSelfK - 0.04);\n                }\n\n                // Future-alternative tiny bias\n                // - if component has few outgoing future edges, be a bit more willing\n                if(cntOutCu <= 1 || cntOutCv <= 1){\n                    cheapK    = clamp13(cheapK + 0.03);\n                    treeK     = clamp13(treeK  + 0.02);\n                    replSelfK = clamp13(replSelfK + 0.02);\n                }\n                // - if many direct alternatives cu-cv and some are geometrically smaller, be stricter\n                if(cntBetween >= 3 && bestBetween < INF){\n                    if(bestBetween * 1000LL <= 950LL * (long long)D[i]){\n                        cheapK    = clamp13(cheapK - 0.02);\n                        replSelfK = clamp13(replSelfK - 0.02);\n                    }\n                }\n                // - if no direct alternative edge exists, be slightly more willing (still not huge)\n                if(cntBetween == 0){\n                    cheapK = clamp13(cheapK + 0.02);\n                }\n\n                long long L = l;\n                long long di = D[i];\n\n                auto leq = [&](long long a, double k)->bool{\n                    return a * 1000LL <= di * (long long)llround(k * 1000.0);\n                };\n\n                // 1) primary guide MST edge\n                if(inMST0[i] && leq(L, treeK)) take = true;\n\n                // 2) cheap by itself\n                if(!take && leq(L, cheapK)) take = true;\n\n                // 3) replacement by guide bottleneck\n                if(!take){\n                    vector<int> md(K);\n                    for(int k=0;k<K;k++) md[k] = hld[k].query_max(u, v, segs[k]);\n                    sort(md.begin(), md.end());\n\n                    int mdUse;\n                    if(mc >= 4) mdUse = md.back();               // optimistic if very important\n                    else if(mc == 0) mdUse = md.front();         // pessimistic if outlier\n                    else mdUse = md[K/2];                        // median\n\n                    if(mdUse > 0){\n                        // geometric sanity gate\n                        if(di * 1000LL <= (long long)mdUse * 1250LL) {\n                            bool ok1 = (L * 1000LL <= (long long)mdUse * (long long)llround(replK * 1000.0));\n                            bool ok2 = (L * 1000LL <= di * (long long)llround(replSelfK * 1000.0));\n                            if(ok1 && ok2) take = true;\n                        }\n                    }\n                }\n            }\n\n            if(take){\n                ufAcc.merge(u,v);\n                comps--;\n                ans = 1;\n            } else {\n                ans = 0;\n            }\n        }\n\n        cout << ans << \"\\n\";\n        cout.flush();\n\n        // remove this edge from each guide tree if present (processed edge is no longer \"future\")\n        for(int k=0;k<K;k++){\n            int child = idxToChild[k][i];\n            if(child != -1){\n                segs[k].set(hld[k].pos[child], 0);\n            }\n        }\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 30, W = 30;\nstatic constexpr int INF = 1e9;\n\nstruct Pet { int x, y, t; };\nstruct Human { int x, y; };\nstruct Rect { int x1, x2, y1, y2; }; // inclusive\n\nstatic inline bool inb(int x,int y){ return 1<=x && x<=H && 1<=y && y<=W; }\nstatic inline int manhattan(int ax,int ay,int bx,int by){ return abs(ax-bx)+abs(ay-by); }\n\nstatic const int dx4[4] = {-1,+1,0,0};\nstatic const int dy4[4] = {0,0,-1,+1};\nstatic const char MOVE_CH[4]  = {'U','D','L','R'};\nstatic const char BUILD_CH[4] = {'u','d','l','r'};\n\nstruct DoorInfo {\n    int x=-1,y=-1;        // door cell (on wall line)\n    int inx=-1, iny=-1;   // adjacent cell inside the rectangle\n    long long score=LLONG_MIN;\n};\n\nstatic void bfs_dist(vector<vector<int>>& dist,\n                     const vector<pair<int,int>>& sources,\n                     const function<bool(int,int)>& passable){\n    dist.assign(H+1, vector<int>(W+1, INF));\n    deque<pair<int,int>> q;\n    for(auto [sx,sy]: sources){\n        if(!inb(sx,sy)) continue;\n        if(!passable(sx,sy)) continue;\n        dist[sx][sy]=0;\n        q.push_back({sx,sy});\n    }\n    while(!q.empty()){\n        auto [x,y]=q.front(); q.pop_front();\n        int nd = dist[x][y]+1;\n        for(int d=0; d<4; d++){\n            int nx=x+dx4[d], ny=y+dy4[d];\n            if(!inb(nx,ny)) continue;\n            if(!passable(nx,ny)) continue;\n            if(dist[nx][ny] > nd){\n                dist[nx][ny]=nd;\n                q.push_back({nx,ny});\n            }\n        }\n    }\n}\n\nstatic char step_by_dist(int x,int y,\n                         const vector<vector<int>>& dist,\n                         const function<bool(int,int)>& passable,\n                         const function<int(int,int)>& tiePenalty){\n    int cur = dist[x][y];\n    int bestDir=-1, bestD=cur, bestPen=INF;\n    for(int d=0; d<4; d++){\n        int nx=x+dx4[d], ny=y+dy4[d];\n        if(!inb(nx,ny)) continue;\n        if(!passable(nx,ny)) continue;\n        int nd = dist[nx][ny];\n        if(nd < bestD){\n            bestD = nd;\n            bestPen = tiePenalty(nx,ny);\n            bestDir = d;\n        }else if(nd == bestD && bestDir!=-1){\n            int pen = tiePenalty(nx,ny);\n            if(pen < bestPen){\n                bestPen = pen;\n                bestDir = d;\n            }\n        }\n    }\n    if(bestDir==-1 || bestD>=cur) return '.';\n    return MOVE_CH[bestDir];\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N; cin >> N;\n    vector<Pet> pets(N);\n    for(int i=0;i<N;i++) cin >> pets[i].x >> pets[i].y >> pets[i].t;\n\n    int M; cin >> M;\n    vector<Human> humans(M);\n    for(int i=0;i<M;i++) cin >> humans[i].x >> humans[i].y;\n\n    auto inside = [&](const Rect& r, int x, int y)->bool{\n        return r.x1 <= x && x <= r.x2 && r.y1 <= y && y <= r.y2;\n    };\n\n    auto make_rect = [&](int corner, int h, int w)->Rect{\n        Rect r;\n        if(corner==0){ r.x1=1; r.x2=h; r.y1=1; r.y2=w; }                   // TL\n        if(corner==1){ r.x1=1; r.x2=h; r.y1=W-w+1; r.y2=W; }               // TR\n        if(corner==2){ r.x1=H-h+1; r.x2=H; r.y1=1; r.y2=w; }               // BL\n        if(corner==3){ r.x1=H-h+1; r.x2=H; r.y1=W-w+1; r.y2=W; }           // BR\n        return r;\n    };\n\n    auto wall_cells_for = [&](const Rect& r)->vector<pair<int,int>>{\n        vector<pair<int,int>> cells;\n        if(r.x1 > 1){\n            int x = r.x1 - 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.x2 < H){\n            int x = r.x2 + 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.y1 > 1){\n            int y = r.y1 - 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        if(r.y2 < W){\n            int y = r.y2 + 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        return cells;\n    };\n\n    auto count_pets_in_rect = [&](const Rect& r)->int{\n        int cnt=0;\n        for(auto &p: pets) if(inside(r,p.x,p.y)) cnt++;\n        return cnt;\n    };\n\n    auto dist_pet_to_rect = [&](const Rect& r)->int{\n        int best = INF;\n        for(auto &p: pets){\n            int dx=0;\n            if(p.x < r.x1) dx = r.x1 - p.x;\n            else if(p.x > r.x2) dx = p.x - r.x2;\n            int dy=0;\n            if(p.y < r.y1) dy = r.y1 - p.y;\n            else if(p.y > r.y2) dy = p.y - r.y2;\n            best = min(best, dx+dy);\n        }\n        return best;\n    };\n\n    auto max_human_dist_to_rect = [&](const Rect& r)->int{\n        int mx=0;\n        for(auto &hu: humans){\n            int dx=0;\n            if(hu.x < r.x1) dx = r.x1 - hu.x;\n            else if(hu.x > r.x2) dx = hu.x - r.x2;\n            int dy=0;\n            if(hu.y < r.y1) dy = r.y1 - hu.y;\n            else if(hu.y > r.y2) dy = hu.y - r.y2;\n            mx = max(mx, dx+dy);\n        }\n        return mx;\n    };\n\n    auto wall_pet_bad_count = [&](const vector<pair<int,int>>& wallCells)->int{\n        int cnt=0;\n        for(auto [x,y]: wallCells){\n            int md=INF;\n            for(auto &p: pets) md = min(md, manhattan(x,y,p.x,p.y));\n            if(md<=1) cnt++;\n        }\n        return cnt;\n    };\n\n    auto choose_best_door = [&](const Rect& r, const vector<pair<int,int>>& wallCells)->DoorInfo{\n        static bool isWall[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) isWall[x][y]=false;\n        for(auto [x,y]: wallCells) isWall[x][y]=true;\n\n        DoorInfo best;\n        for(auto [wx,wy]: wallCells){\n            int inx=-1, iny=-1;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(inb(nx,ny) && inside(r,nx,ny)){ inx=nx; iny=ny; break; }\n            }\n            if(inx==-1) continue;\n\n            bool okOutside=false;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(inside(r,nx,ny)) continue;\n                if(isWall[nx][ny]) continue;\n                okOutside=true;\n            }\n            if(!okOutside) continue;\n\n            int minPetDist = 1000;\n            for(auto &p: pets) minPetDist = min(minPetDist, manhattan(wx,wy,p.x,p.y));\n\n            long long sumHumanDist=0;\n            for(auto &h: humans) sumHumanDist += manhattan(h.x,h.y, inx,iny);\n\n            int borderPenalty = (wx==1 || wx==H || wy==1 || wy==W) ? 50 : 0;\n\n            DoorInfo cand;\n            cand.x=wx; cand.y=wy; cand.inx=inx; cand.iny=iny;\n            cand.score = 280LL*minPetDist - 1LL*sumHumanDist - borderPenalty;\n\n            if(cand.score > best.score) best = cand;\n        }\n        return best;\n    };\n\n    // ---- Choose rectangle: corner + small (fast seal), single door ----\n    Rect bestRect{1,6,1,6};\n    DoorInfo bestDoor;\n    double bestEval = -1e100;\n\n    for(int corner=0; corner<4; corner++){\n        for(int h=5; h<=15; h++){\n            for(int w=5; w<=15; w++){\n                Rect r = make_rect(corner,h,w);\n                int area = (r.x2-r.x1+1)*(r.y2-r.y1+1);\n\n                auto wallCells = wall_cells_for(r);\n                int wallLen = (int)wallCells.size();\n                if(wallLen==0) continue;\n\n                // avoid initial occupancy on wall cells\n                bool bad=false;\n                for(auto [x,y]: wallCells){\n                    for(auto &p: pets) if(p.x==x && p.y==y){ bad=true; break; }\n                    if(bad) break;\n                    for(auto &hu: humans) if(hu.x==x && hu.y==y){ bad=true; break; }\n                    if(bad) break;\n                }\n                if(bad) continue;\n\n                DoorInfo door = choose_best_door(r, wallCells);\n                if(door.x==-1) continue;\n\n                int petsIn = count_pets_in_rect(r);\n                int minPetToRect = dist_pet_to_rect(r);\n                int maxHumanDist = max_human_dist_to_rect(r);\n                int badWallCnt = wall_pet_bad_count(wallCells);\n\n                // Robust evaluation (fast + low risk)\n                double val = (double)area / 900.0;\n                val *= pow(0.5, 3.0 * petsIn);\n                val *= (1.0 + 0.05 * minPetToRect);\n                val *= exp(-0.06 * maxHumanDist);\n                val *= exp(-0.12 * wallLen);\n                val *= exp(-0.55 * badWallCnt);\n\n                if(val > bestEval){\n                    bestEval = val;\n                    bestRect = r;\n                    bestDoor = door;\n                }\n            }\n        }\n    }\n\n    // Fallback safety\n    if(bestDoor.x==-1){\n        bestRect = make_rect(0, 8, 8);\n        auto wc = wall_cells_for(bestRect);\n        bestDoor = choose_best_door(bestRect, wc);\n        if(bestDoor.x==-1){\n            // ultra emergency: no partitions at all\n            bestDoor.x = 1; bestDoor.y = 1;\n            bestDoor.inx = 1; bestDoor.iny = 2;\n        }\n    }\n\n    Rect rect = bestRect;\n    auto wallCells = wall_cells_for(rect);\n\n    static bool blocked[H+1][W+1];\n    static bool targetWall[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n        blocked[x][y]=false;\n        targetWall[x][y]=false;\n    }\n\n    for(auto [x,y]: wallCells) targetWall[x][y]=true;\n    // keep one door cell open until the end\n    targetWall[bestDoor.x][bestDoor.y]=false;\n\n    auto insideNow = [&](int x,int y){ return inside(rect,x,y); };\n    pair<int,int> gatherPoint = {(rect.x1+rect.x2)/2, (rect.y1+rect.y2)/2};\n\n    auto compute_occupancy = [&](vector<vector<bool>>& petAt, vector<vector<bool>>& humanAt){\n        petAt.assign(H+1, vector<bool>(W+1,false));\n        humanAt.assign(H+1, vector<bool>(W+1,false));\n        for(auto &p: pets) petAt[p.x][p.y]=true;\n        for(auto &h: humans) humanAt[h.x][h.y]=true;\n    };\n\n    auto canBuild = [&](int tx,int ty,\n                        const vector<vector<bool>>& petAt,\n                        const vector<vector<bool>>& humanAt)->bool{\n        if(!inb(tx,ty)) return false;\n        if(petAt[tx][ty] || humanAt[tx][ty]) return false;\n        for(int d=0; d<4; d++){\n            int nx=tx+dx4[d], ny=ty+dy4[d];\n            if(inb(nx,ny) && petAt[nx][ny]) return false;\n        }\n        return true;\n    };\n\n    std::mt19937 rng(0);\n\n    for(int turn=0; turn<300; turn++){\n        vector<vector<bool>> petAt, humanAt;\n        compute_occupancy(petAt, humanAt);\n\n        int remWalls=0;\n        for(auto [x,y]: wallCells){\n            if(targetWall[x][y] && !blocked[x][y]) remWalls++;\n        }\n\n        bool allInside=true;\n        for(auto &h: humans) if(!insideNow(h.x,h.y)) { allInside=false; break; }\n\n        bool doorClosed = blocked[bestDoor.x][bestDoor.y];\n\n        vector<char> act(M,'.');\n\n        // ---- (A) decide builds first ----\n        // (A-1) close door if everything else done and all humans inside\n        if(remWalls==0 && allInside && !doorClosed){\n            if(canBuild(bestDoor.x,bestDoor.y,petAt,humanAt)){\n                bool someoneOn=false;\n                for(auto &h: humans) if(h.x==bestDoor.x && h.y==bestDoor.y) { someoneOn=true; break; }\n                if(!someoneOn){\n                    for(int i=0;i<M;i++){\n                        int hx=humans[i].x, hy=humans[i].y;\n                        if(manhattan(hx,hy,bestDoor.x,bestDoor.y)!=1) continue;\n                        for(int dir=0; dir<4; dir++){\n                            if(hx+dx4[dir]==bestDoor.x && hy+dy4[dir]==bestDoor.y){\n                                act[i]=BUILD_CH[dir];\n                                break;\n                            }\n                        }\n                        if(act[i]!='.') break;\n                    }\n                }\n            }\n        }\n\n        // (A-2) build remaining target walls; avoid duplicates with reservation\n        static bool reserved[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) reserved[x][y]=false;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for(int idx=0; idx<M; idx++){\n            int i = order[idx];\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            int bestDir=-1;\n            // prefer building if adjacent\n            for(int dir=0; dir<4; dir++){\n                int tx=hx+dx4[dir], ty=hy+dy4[dir];\n                if(!inb(tx,ty)) continue;\n                if(!(targetWall[tx][ty] && !blocked[tx][ty])) continue;\n                if(reserved[tx][ty]) continue;\n                if(!canBuild(tx,ty,petAt,humanAt)) continue;\n                bestDir = dir;\n                reserved[tx][ty]=true;\n                break;\n            }\n            if(bestDir!=-1) act[i]=BUILD_CH[bestDir];\n        }\n\n        // compute willBlock (for move legality)\n        static bool willBlock[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) willBlock[x][y]=false;\n\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='u') dir=0;\n            if(c=='d') dir=1;\n            if(c=='l') dir=2;\n            if(c=='r') dir=3;\n            if(dir==-1) continue;\n            int tx=humans[i].x+dx4[dir], ty=humans[i].y+dy4[dir];\n            if(inb(tx,ty) && !blocked[tx][ty] && canBuild(tx,ty,petAt,humanAt)){\n                willBlock[tx][ty]=true;\n            }\n        }\n\n        // ---- (B) movement planning with willBlock treated as impassable ----\n        auto passAll = [&](int x,int y)->bool{\n            return inb(x,y) && !blocked[x][y] && !willBlock[x][y];\n        };\n\n        // build goals: cells adjacent to remaining target walls (global, not only inside)\n        vector<pair<int,int>> buildGoals;\n        if(remWalls>0){\n            static bool mark[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark[x][y]=false;\n            for(auto [wx,wy]: wallCells){\n                if(!(targetWall[wx][wy] && !blocked[wx][wy])) continue;\n                for(int d=0; d<4; d++){\n                    int nx=wx+dx4[d], ny=wy+dy4[d];\n                    if(inb(nx,ny) && passAll(nx,ny) && !mark[nx][ny]){\n                        mark[nx][ny]=true;\n                        buildGoals.push_back({nx,ny});\n                    }\n                }\n            }\n        }\n\n        vector<vector<int>> distBuild, distGather, distClose;\n        if(!buildGoals.empty()) bfs_dist(distBuild, buildGoals, passAll);\n        else distBuild.assign(H+1, vector<int>(W+1, INF));\n\n        bfs_dist(distGather, {gatherPoint}, passAll);\n\n        // close goal: inside neighbor of door (standing there allows building the door)\n        if(remWalls==0 && allInside && !doorClosed){\n            bfs_dist(distClose, {{bestDoor.inx,bestDoor.iny}}, passAll);\n        }else{\n            distClose.assign(H+1, vector<int>(W+1, INF));\n        }\n\n        auto tiePenalty = [&](int x,int y)->int{\n            // discourage standing on the door cell itself\n            if(x==bestDoor.x && y==bestDoor.y) return 50;\n            return 0;\n        };\n\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            if(remWalls>0 && distBuild[hx][hy] < INF){\n                // KEY CHANGE: while walls remain, always prioritize building positions\n                act[i] = step_by_dist(hx,hy,distBuild,passAll,tiePenalty);\n            }else if(remWalls==0 && allInside && !doorClosed && distClose[hx][hy] < INF){\n                act[i] = step_by_dist(hx,hy,distClose,passAll,tiePenalty);\n            }else if(!allInside && distGather[hx][hy] < INF){\n                act[i] = step_by_dist(hx,hy,distGather,passAll,tiePenalty);\n            }else{\n                act[i] = '.';\n            }\n        }\n\n        // output\n        string out; out.reserve(M);\n        for(int i=0;i<M;i++) out.push_back(act[i]);\n        cout << out << \"\\n\" << flush;\n\n        // ---- local sim update ----\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n            if(willBlock[x][y]) blocked[x][y]=true;\n        }\n\n        // apply moves\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='U') dir=0;\n            if(c=='D') dir=1;\n            if(c=='L') dir=2;\n            if(c=='R') dir=3;\n            if(dir==-1) continue;\n            int nx=humans[i].x+dx4[dir], ny=humans[i].y+dy4[dir];\n            if(inb(nx,ny) && !blocked[nx][ny] && !willBlock[nx][ny]){\n                humans[i].x=nx; humans[i].y=ny;\n            }\n        }\n\n        // read pet moves\n        for(int i=0;i<N;i++){\n            string s; cin >> s;\n            if(s==\".\") continue;\n            for(char c: s){\n                int dir=-1;\n                if(c=='U') dir=0;\n                if(c=='D') dir=1;\n                if(c=='L') dir=2;\n                if(c=='R') dir=3;\n                if(dir==-1) continue;\n                int nx=pets[i].x+dx4[dir], ny=pets[i].y+dy4[dir];\n                if(inb(nx,ny) && !blocked[nx][ny]){\n                    pets[i].x=nx; pets[i].y=ny;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int V = N * N;\nstatic constexpr int L = 200;\nstatic constexpr int INF = 1e9;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() : st(chrono::high_resolution_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\nstatic inline char dirCh(int d) {\n    static const char dc[4] = {'U','D','L','R'};\n    return dc[d];\n}\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct XorShift {\n    uint64_t s0, s1;\n    XorShift(uint64_t seed = 1) { reseed(seed); }\n    void reseed(uint64_t seed) {\n        s0 = splitmix64(seed);\n        s1 = splitmix64(s0);\n        if ((s0 | s1) == 0) s1 = 1;\n    }\n    uint64_t nextU64() {\n        uint64_t x = s0, y = s1;\n        s0 = y;\n        x ^= x << 23;\n        s1 = x ^ y ^ (x >> 17) ^ (y >> 26);\n        return s1 + y;\n    }\n    uint32_t nextU32() { return (uint32_t)(nextU64() >> 32); }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic string pad_to_200(string s) {\n    if ((int)s.size() >= L) { s.resize(L); return s; }\n    if (s.empty()) return string(L, 'U');\n    s.resize(L, s.back());\n    return s;\n}\nstatic string tile_to_200(const string &base) {\n    if (base.empty()) return string(L, 'U');\n    string out; out.reserve(L);\n    while ((int)out.size() < L) out += base;\n    out.resize(L);\n    return out;\n}\nstatic string stretch_runs_to_200(const string &path, int factor) {\n    if (path.empty()) return string(L, 'U');\n    string out; out.reserve(L);\n    for (int i = 0; i < (int)path.size() && (int)out.size() < L; ) {\n        int j = i;\n        while (j < (int)path.size() && path[j] == path[i]) j++;\n        int len = (j - i) * factor;\n        for (int k = 0; k < len && (int)out.size() < L; k++) out.push_back(path[i]);\n        i = j;\n    }\n    while ((int)out.size() < L) out.push_back(path.back());\n    return out;\n}\n\nstruct EvaluatorFullDouble {\n    int s, t;\n    double p, q;\n    const int (*nxt)[4];\n    vector<double> dist, ndist;\n    EvaluatorFullDouble(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p(p_), q(1.0 - p_), nxt(nxt_) {\n        dist.assign(V, 0.0);\n        ndist.assign(V, 0.0);\n    }\n    double eval(const string &seq) {\n        fill(dist.begin(), dist.end(), 0.0);\n        dist[s] = 1.0;\n        double E = 0.0;\n        for (int step = 0; step < (int)seq.size(); step++) {\n            fill(ndist.begin(), ndist.end(), 0.0);\n            int d = dirId(seq[step]);\n            double hit = 0.0;\n            for (int pos = 0; pos < V; pos++) {\n                double pr = dist[pos];\n                if (pr <= 0.0) continue;\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    ndist[pos] += pr;\n                } else {\n                    double st = pr * p;\n                    double mv = pr * q;\n                    ndist[pos] += st;\n                    if (np == t) hit += mv;\n                    else ndist[np] += mv;\n                }\n            }\n            dist.swap(ndist);\n            E += hit * (401.0 - (step + 1));\n        }\n        return E;\n    }\n};\n\n// ===== Constructors =====\n\nstatic string bfs_shortest_path(int s, int t, const int nxt[V][4]) {\n    vector<int> prev(V, -1);\n    vector<char> prevC(V, '?');\n    deque<int> dq;\n    dq.push_back(s);\n    prev[s] = s;\n    while (!dq.empty()) {\n        int x = dq.front(); dq.pop_front();\n        if (x == t) break;\n        for (int d = 0; d < 4; d++) {\n            int y = nxt[x][d];\n            if (y == x) continue;\n            if (prev[y] != -1) continue;\n            prev[y] = x;\n            prevC[y] = dirCh(d);\n            dq.push_back(y);\n        }\n    }\n    if (prev[t] == -1) return \"D\";\n    string path;\n    int cur = t;\n    while (cur != s) {\n        path.push_back(prevC[cur]);\n        cur = prev[cur];\n    }\n    reverse(path.begin(), path.end());\n    if (path.empty()) path = \"D\";\n    return path;\n}\n\n// Dijkstra on (cell, prevDir) minimizing length + turnPenalty*turns\nstatic string min_turn_path(int s, int t, const int nxt[V][4], int turnPenalty) {\n    const int PD = 5; // 0..3 prevDir, 4=start\n    int S = s * PD + 4;\n\n    vector<int> dist(V * PD, INF);\n    vector<int> prv(V * PD, -1);\n    vector<char> prvMove(V * PD, '?');\n\n    using P = pair<int,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    dist[S] = 0;\n    pq.push({0, S});\n\n    int bestEnd = -1;\n    while (!pq.empty()) {\n        auto [cd, st] = pq.top(); pq.pop();\n        if (cd != dist[st]) continue;\n        int cell = st / PD;\n        int prevDir = st % PD;\n        if (cell == t) { bestEnd = st; break; }\n\n        for (int d = 0; d < 4; d++) {\n            int nc = nxt[cell][d];\n            if (nc == cell) continue;\n            int ns = nc * PD + d;\n            int add = 1;\n            if (prevDir != 4 && prevDir != d) add += turnPenalty;\n            int nd = cd + add;\n            if (nd < dist[ns]) {\n                dist[ns] = nd;\n                prv[ns] = st;\n                prvMove[ns] = dirCh(d);\n                pq.push({nd, ns});\n            }\n        }\n    }\n\n    if (bestEnd == -1) return bfs_shortest_path(s, t, nxt);\n\n    string path;\n    int cur = bestEnd;\n    while (cur != S) {\n        path.push_back(prvMove[cur]);\n        cur = prv[cur];\n    }\n    reverse(path.begin(), path.end());\n    if (path.empty()) path = \"D\";\n    return path;\n}\n\nstatic string greedy_lookahead_200(int s, int t, double p, const int nxt[V][4], const vector<int>& distToT) {\n    double q = 1.0 - p;\n    vector<double> cur(V, 0.0), nd(V, 0.0);\n    cur[s] = 1.0;\n\n    string out; out.reserve(L);\n    for (int step = 0; step < L; step++) {\n        int bestD = 0;\n        double bestVal = -1e100;\n\n        for (int d = 0; d < 4; d++) {\n            fill(nd.begin(), nd.end(), 0.0);\n            double hit = 0.0, expDist = 0.0;\n            for (int pos = 0; pos < V; pos++) {\n                double pr = cur[pos];\n                if (pr <= 0.0) continue;\n                int np = nxt[pos][d];\n                if (np == pos) nd[pos] += pr;\n                else {\n                    double st = pr * p;\n                    double mv = pr * q;\n                    nd[pos] += st;\n                    if (np == t) hit += mv;\n                    else nd[np] += mv;\n                }\n            }\n            for (int pos = 0; pos < V; pos++) expDist += nd[pos] * distToT[pos];\n            double val = 0.30 * (401.0 - (step + 1)) * hit - 1.7 * expDist;\n            if (val > bestVal) { bestVal = val; bestD = d; }\n        }\n\n        // apply bestD\n        fill(nd.begin(), nd.end(), 0.0);\n        for (int pos = 0; pos < V; pos++) {\n            double pr = cur[pos];\n            if (pr <= 0.0) continue;\n            int np = nxt[pos][bestD];\n            if (np == pos) nd[pos] += pr;\n            else {\n                double st = pr * p;\n                double mv = pr * q;\n                nd[pos] += st;\n                if (np != t) nd[np] += mv;\n            }\n        }\n        cur.swap(nd);\n        out.push_back(dirCh(bestD));\n    }\n    return out;\n}\n\n// ===== Beam Search (constructor) =====\n\nstruct Meta { int parent; char mv; };\nstruct BeamCand {\n    int meta;\n    double exp;\n    double key;\n    double rem;\n    array<double, V> prob;\n};\n\nstatic string beam_search_200(\n    int s, int t, double p, const int nxt[V][4], const vector<int>& distToT,\n    Timer &timer, double endTime, XorShift &rng\n) {\n    double q = 1.0 - p;\n    int W = (p >= 0.35 ? 900 : 750);\n    int keepKey = (int)(W * 0.55);\n    int keepExp = (int)(W * 0.25);\n    int keepRem = W - keepKey - keepExp;\n\n    vector<Meta> meta;\n    meta.reserve(260000);\n    meta.push_back({-1, '?'});\n\n    vector<BeamCand> cur;\n    cur.reserve(W);\n\n    BeamCand root;\n    root.meta = 0;\n    root.exp = 0.0;\n    root.key = 0.0;\n    root.rem = 1.0;\n    root.prob.fill(0.0);\n    root.prob[s] = 1.0;\n    cur.push_back(root);\n\n    for (int depth = 0; depth < L; depth++) {\n        if (timer.elapsed() > endTime) break;\n\n        vector<BeamCand> all;\n        all.reserve(cur.size() * 4);\n\n        for (auto &c : cur) {\n            if (c.rem < 1e-15) continue;\n            for (int d = 0; d < 4; d++) {\n                BeamCand ch;\n                ch.prob.fill(0.0);\n                double hit = 0.0;\n\n                for (int pos = 0; pos < V; pos++) {\n                    double pr = c.prob[pos];\n                    if (pr <= 0.0) continue;\n                    int np = nxt[pos][d];\n                    if (np == pos) ch.prob[pos] += pr;\n                    else {\n                        double st = pr * p;\n                        double mv = pr * q;\n                        ch.prob[pos] += st;\n                        if (np == t) hit += mv;\n                        else ch.prob[np] += mv;\n                    }\n                }\n\n                int turn = depth + 1;\n                ch.exp = c.exp + hit * (401.0 - turn);\n\n                double rem = 0.0, sumd = 0.0;\n                int mind = INF;\n                for (int pos = 0; pos < V; pos++) {\n                    double pr = ch.prob[pos];\n                    if (pr <= 0.0) continue;\n                    rem += pr;\n                    sumd += pr * distToT[pos];\n                    mind = min(mind, distToT[pos]);\n                }\n                ch.rem = rem;\n\n                double key = ch.exp;\n                int remainingSteps = L - turn;\n                if (rem > 1e-15 && mind <= remainingSteps) {\n                    double avgd = sumd / rem;\n                    double estTime = (double)turn + avgd / max(1e-9, q);\n                    estTime = min(estTime, 200.0);\n                    double estAdd = rem * max(0.0, 401.0 - estTime);\n                    key = ch.exp + 0.85 * estAdd + 8.0 * (1.0 - rem);\n                }\n                key += (rng.nextDouble() - 0.5) * 1e-6;\n                ch.key = key;\n\n                meta.push_back({c.meta, dirCh(d)});\n                ch.meta = (int)meta.size() - 1;\n\n                all.push_back(std::move(ch));\n            }\n        }\n        if (all.empty()) break;\n\n        int M = (int)all.size();\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        vector<char> chosen(M, 0);\n        vector<int> picked;\n        picked.reserve(min(W, M));\n\n        auto pickTop = [&](int need, auto cmp) {\n            if (need <= 0) return;\n            vector<int> id = idx;\n            need = min(need, (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(), cmp);\n            id.resize(need);\n            sort(id.begin(), id.end(), cmp);\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) { chosen[i] = 1; picked.push_back(i); }\n            }\n        };\n\n        pickTop(keepKey, [&](int a, int b){ return all[a].key > all[b].key; });\n        pickTop(keepExp, [&](int a, int b){ return all[a].exp > all[b].exp; });\n        pickTop(keepRem, [&](int a, int b){ return all[a].rem < all[b].rem; });\n\n        if ((int)picked.size() < min(W, M)) {\n            vector<int> id = idx;\n            int need = min(W - (int)picked.size(), (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(),\n                        [&](int a, int b){ return all[a].key > all[b].key; });\n            id.resize(need);\n            sort(id.begin(), id.end(), [&](int a, int b){ return all[a].key > all[b].key; });\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) { chosen[i] = 1; picked.push_back(i); }\n            }\n        }\n\n        vector<BeamCand> nb;\n        nb.reserve(picked.size());\n        for (int i : picked) nb.push_back(std::move(all[i]));\n        cur.swap(nb);\n    }\n\n    int bestMeta = cur[0].meta;\n    double bestExp = cur[0].exp;\n    for (auto &c : cur) if (c.exp > bestExp) { bestExp = c.exp; bestMeta = c.meta; }\n\n    string ans;\n    int node = bestMeta;\n    while (node != 0) {\n        ans.push_back(meta[node].mv);\n        node = meta[node].parent;\n    }\n    reverse(ans.begin(), ans.end());\n    return pad_to_200(ans);\n}\n\n// ===== DP for fast delta on single edits (whole string) =====\n\nstruct DPAll {\n    int s, t;\n    float p, q;\n    const int (*nxt)[4];\n\n    string seq;                 // length L\n    vector<float> dist;         // (L+1)*V\n    vector<double> B;           // (L+1)*V\n    double score;               // expected score = B[0][s]\n\n    DPAll(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p((float)p_), q((float)(1.0 - p_)), nxt(nxt_) {\n        seq.assign(L, 'U');\n        dist.assign((L + 1) * V, 0.0f);\n        B.assign((L + 1) * V, 0.0);\n        score = 0.0;\n    }\n\n    inline float* distAt(int k) { return dist.data() + k * V; }\n    inline const float* distAt(int k) const { return dist.data() + k * V; }\n    inline double* BAt(int k) { return B.data() + k * V; }\n    inline const double* BAt(int k) const { return B.data() + k * V; }\n\n    void build(const string &init) {\n        seq = init;\n        fill(dist.begin(), dist.end(), 0.0f);\n        distAt(0)[s] = 1.0f;\n\n        for (int k = 0; k < L; k++) {\n            const float* cur = distAt(k);\n            float* nx = distAt(k + 1);\n            memset(nx, 0, sizeof(float) * V);\n            int d = dirId(seq[k]);\n            for (int pos = 0; pos < V; pos++) {\n                float pr = cur[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    nx[pos] += pr;\n                } else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    nx[pos] += st;\n                    if (np != t) nx[np] += mv;\n                }\n            }\n        }\n\n        // B[L] = 0\n        {\n            double* BL = BAt(L);\n            for (int pos = 0; pos < V; pos++) BL[pos] = 0.0;\n        }\n        for (int k = L - 1; k >= 0; k--) {\n            const double* Bnext = BAt(k + 1);\n            double* Bcur = BAt(k);\n            int d = dirId(seq[k]);\n            double reward = (401.0 - (k + 1));\n            for (int pos = 0; pos < V; pos++) {\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    Bcur[pos] = Bnext[pos];\n                } else {\n                    double val = (double)p * Bnext[pos];\n                    if (np == t) val += (double)q * reward;\n                    else val += (double)q * Bnext[np];\n                    Bcur[pos] = val;\n                }\n            }\n        }\n        score = BAt(0)[s];\n    }\n\n    // Recompute forward dist from step `from` (dist[from] assumed correct)\n    void forwardUpdate(int from) {\n        for (int k = from; k < L; k++) {\n            const float* cur = distAt(k);\n            float* nx = distAt(k + 1);\n            memset(nx, 0, sizeof(float) * V);\n            int d = dirId(seq[k]);\n            for (int pos = 0; pos < V; pos++) {\n                float pr = cur[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) nx[pos] += pr;\n                else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    nx[pos] += st;\n                    if (np != t) nx[np] += mv;\n                }\n            }\n        }\n    }\n\n    // Recompute backward B from step `from` down to 0 (B[from+1] assumed correct)\n    void backwardUpdate(int from) {\n        for (int k = from; k >= 0; k--) {\n            const double* Bnext = BAt(k + 1);\n            double* Bcur = BAt(k);\n            int d = dirId(seq[k]);\n            double reward = (401.0 - (k + 1));\n            for (int pos = 0; pos < V; pos++) {\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    Bcur[pos] = Bnext[pos];\n                } else {\n                    double val = (double)p * Bnext[pos];\n                    if (np == t) val += (double)q * reward;\n                    else val += (double)q * Bnext[np];\n                    Bcur[pos] = val;\n                }\n            }\n        }\n    }\n\n    // Exact delta for changing seq[idx] to newc (single edit) in O(V).\n    double deltaSingle(int idx, char newc) const {\n        int dOld = dirId(seq[idx]);\n        int dNew = dirId(newc);\n        if (dOld == dNew) return 0.0;\n\n        const float* di = distAt(idx);\n        const double* Bnext = BAt(idx + 1);\n        double reward = (401.0 - (idx + 1));\n\n        auto Q = [&](int pos, int d) -> double {\n            int np = nxt[pos][d];\n            if (np == pos) return Bnext[pos];\n            double val = (double)p * Bnext[pos];\n            if (np == t) val += (double)q * reward;\n            else val += (double)q * Bnext[np];\n            return val;\n        };\n\n        double delta = 0.0;\n        for (int pos = 0; pos < V; pos++) {\n            float pr = di[pos];\n            if (pr <= 0.0f) continue;\n            delta += (double)pr * (Q(pos, dNew) - Q(pos, dOld));\n        }\n        return delta;\n    }\n\n    void applySingleAccepted(int idx, char newc) {\n        seq[idx] = newc;\n        forwardUpdate(idx);\n        backwardUpdate(idx);\n        score = BAt(0)[s];\n    }\n\n    // Apply a segment modification (already changed seq[l..r-1]).\n    // Need forward from l and backward from (r-1).\n    void applySegmentChanged(int l, int r) {\n        if (l < 0) l = 0;\n        if (r > L) r = L;\n        if (l >= r) return;\n        forwardUpdate(l);\n        backwardUpdate(r - 1);\n        score = BAt(0)[s];\n    }\n};\n\n// Greedy improvement sweep on suffix using deltaSingle (cheap)\nstatic void greedySuffixImprove(DPAll &dp, int startIdx, Timer &timer, double endTime) {\n    startIdx = max(0, min(L - 1, startIdx));\n    for (int idx = L - 1; idx >= startIdx; idx--) {\n        if (timer.elapsed() > endTime) return;\n        char orig = dp.seq[idx];\n        double bestDelta = 0.0;\n        char bestC = orig;\n        for (int d = 0; d < 4; d++) {\n            char c = dirCh(d);\n            if (c == orig) continue;\n            double delta = dp.deltaSingle(idx, c);\n            if (delta > bestDelta) { bestDelta = delta; bestC = c; }\n        }\n        if (bestC != orig) dp.applySingleAccepted(idx, bestC);\n    }\n}\n\n// SA using O(V) delta for single changes, rare segment moves with rebuild-from.\nstatic void SA_fastDelta(\n    DPAll &dp,\n    EvaluatorFullDouble &fullEval,\n    double &globalBestFull,\n    string &globalBestStr,\n    Timer &timer,\n    double endTime,\n    XorShift &rng\n) {\n    double bestIncSeen = dp.score;\n    int stagn = 0;\n\n    auto validate = [&]() {\n        double scFull = fullEval.eval(dp.seq);\n        if (scFull > globalBestFull) { globalBestFull = scFull; globalBestStr = dp.seq; }\n    };\n\n    validate();\n\n    auto sampleIndex = [&]() {\n        // mostly end-biased, sometimes uniform\n        if (rng.nextDouble() < 0.25) return rng.nextInt(0, L - 1);\n        int a = rng.nextInt(0, L - 1);\n        int b = rng.nextInt(0, L - 1);\n        return max(a, b);\n    };\n\n    while (timer.elapsed() < endTime) {\n        double now = timer.elapsed();\n        double frac = min(1.0, max(0.0, (now - (endTime - 1.0)) / max(1e-9, 1.0)));\n        double T0 = 4.5, T1 = 0.06;\n        if (stagn > 7000) T0 *= 1.2;\n        double temp = T0 * pow(T1 / T0, frac);\n\n        int r = rng.nextInt(0, 999);\n\n        if (r < 930) {\n            // single-position move, evaluated by exact deltaSingle\n            int idx = sampleIndex();\n            char orig = dp.seq[idx];\n            char nc = orig;\n\n            if (r < 520) {\n                do { nc = dirCh(rng.nextInt(0, 3)); } while (nc == orig);\n            } else {\n                // turn-smoothing: copy neighbor if possible\n                if (idx == 0) nc = dp.seq[1];\n                else if (idx == L - 1) nc = dp.seq[L - 2];\n                else {\n                    if (rng.nextDouble() < 0.5) nc = dp.seq[idx - 1];\n                    else nc = dp.seq[idx + 1];\n                }\n                if (nc == orig) continue;\n            }\n\n            double delta = dp.deltaSingle(idx, nc);\n            if (delta == 0.0) { stagn++; continue; }\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else if (exp(delta / temp) > rng.nextDouble()) accept = true;\n\n            if (!accept) { stagn++; continue; }\n\n            dp.applySingleAccepted(idx, nc);\n\n            if (dp.score > bestIncSeen + 1e-9) {\n                bestIncSeen = dp.score;\n                validate();\n                stagn = 0;\n            } else {\n                if ((rng.nextInt(0, 255) == 0)) validate();\n                stagn++;\n            }\n        } else {\n            // rare segment move: random rewrite or reverse\n            int l = rng.nextInt(0, L - 2);\n            int rr = rng.nextInt(l + 1, min(L - 1, l + 25));\n            int rlen = rr - l + 1;\n\n            string old = dp.seq.substr(l, rlen);\n            double oldScore = dp.score;\n\n            if (rng.nextDouble() < 0.5) {\n                // rewrite\n                for (int i = l; i <= rr; i++) dp.seq[i] = dirCh(rng.nextInt(0, 3));\n            } else {\n                // reverse\n                reverse(dp.seq.begin() + l, dp.seq.begin() + rr + 1);\n            }\n\n            dp.applySegmentChanged(l, rr + 1);\n            double delta = dp.score - oldScore;\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else if (exp(delta / temp) > rng.nextDouble()) accept = true;\n\n            if (!accept) {\n                // revert\n                for (int i = 0; i < rlen; i++) dp.seq[l + i] = old[i];\n                dp.applySegmentChanged(l, rr + 1);\n                stagn++;\n            } else {\n                if (dp.score > bestIncSeen + 1e-9) {\n                    bestIncSeen = dp.score;\n                    validate();\n                    stagn = 0;\n                } else {\n                    stagn++;\n                }\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TL = 1.97;\n    const double BEAM_END = 0.60;\n\n    int si, sj, ti, tj;\n    double p;\n    cin >> si >> sj >> ti >> tj >> p;\n\n    vector<string> h(N);\n    for (int i = 0; i < N; i++) cin >> h[i];\n    vector<string> v(N - 1);\n    for (int i = 0; i < N - 1; i++) cin >> v[i];\n\n    auto id = [&](int r, int c){ return r * N + c; };\n    int s = id(si, sj);\n    int t = id(ti, tj);\n\n    static int nxt[V][4];\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int cur = id(r, c);\n        // U\n        if (r == 0) nxt[cur][0] = cur;\n        else nxt[cur][0] = (v[r-1][c] == '0') ? id(r-1, c) : cur;\n        // D\n        if (r == N-1) nxt[cur][1] = cur;\n        else nxt[cur][1] = (v[r][c] == '0') ? id(r+1, c) : cur;\n        // L\n        if (c == 0) nxt[cur][2] = cur;\n        else nxt[cur][2] = (h[r][c-1] == '0') ? id(r, c-1) : cur;\n        // R\n        if (c == N-1) nxt[cur][3] = cur;\n        else nxt[cur][3] = (h[r][c] == '0') ? id(r, c+1) : cur;\n    }\n\n    // dist-to-target (BFS) for heuristics\n    vector<int> distToT(V, INF);\n    {\n        deque<int> dq;\n        distToT[t] = 0;\n        dq.push_back(t);\n        while (!dq.empty()) {\n            int x = dq.front(); dq.pop_front();\n            int dx = distToT[x] + 1;\n            for (int d = 0; d < 4; d++) {\n                int y = nxt[x][d];\n                if (y == x) continue;\n                if (distToT[y] > dx) {\n                    distToT[y] = dx;\n                    dq.push_back(y);\n                }\n            }\n        }\n    }\n\n    // deterministic seed from input\n    uint64_t seed = 0;\n    seed = splitmix64(seed ^ (uint64_t)si);\n    seed = splitmix64(seed ^ (uint64_t)sj);\n    seed = splitmix64(seed ^ (uint64_t)ti);\n    seed = splitmix64(seed ^ (uint64_t)tj);\n    seed = splitmix64(seed ^ (uint64_t)llround(p * 1000000.0));\n    for (auto &row : h) for (char c : row) seed = splitmix64(seed ^ (uint64_t)c);\n    for (auto &row : v) for (char c : row) seed = splitmix64(seed ^ (uint64_t)c);\n    XorShift rng(seed);\n\n    EvaluatorFullDouble fullEval(s, t, p, nxt);\n\n    // Build diverse initial candidates\n    vector<string> cands;\n    cands.reserve(48);\n\n    string sp = bfs_shortest_path(s, t, nxt);\n    cands.push_back(tile_to_200(sp));\n    cands.push_back(stretch_runs_to_200(sp, 2));\n    cands.push_back(stretch_runs_to_200(sp, 3));\n    cands.push_back(pad_to_200(sp));\n\n    for (int tp : {2, 5, 10, 20, 40}) {\n        string mt = min_turn_path(s, t, nxt, tp);\n        cands.push_back(tile_to_200(mt));\n        cands.push_back(stretch_runs_to_200(mt, 2));\n        cands.push_back(stretch_runs_to_200(mt, 3));\n        cands.push_back(pad_to_200(mt));\n    }\n\n    cands.push_back(greedy_lookahead_200(s, t, p, nxt, distToT));\n    cands.push_back(beam_search_200(s, t, p, nxt, distToT, timer, BEAM_END, rng));\n\n    // Score candidates by full evaluation\n    vector<pair<double,string>> scored;\n    scored.reserve(cands.size());\n    for (auto &ss : cands) scored.push_back({fullEval.eval(ss), ss});\n    sort(scored.begin(), scored.end(), [&](auto &a, auto &b){ return a.first > b.first; });\n\n    double globalBestFull = scored[0].first;\n    string globalBestStr = scored[0].second;\n\n    // Multi-start local search\n    int K = min(3, (int)scored.size());\n    vector<double> w(K, 0.0);\n    if (K == 1) w[0] = 1.0;\n    else if (K == 2) { w[0] = 0.70; w[1] = 0.30; }\n    else { w[0] = 0.60; w[1] = 0.25; w[2] = 0.15; }\n\n    double start = timer.elapsed();\n    double remaining = TL - start;\n    if (remaining < 0.03) {\n        cout << pad_to_200(globalBestStr) << \"\\n\";\n        return 0;\n    }\n\n    for (int k = 0; k < K; k++) {\n        if (timer.elapsed() >= TL) break;\n        double slice = remaining * w[k];\n        double endTime = min(TL, timer.elapsed() + slice);\n\n        DPAll dp(s, t, p, nxt);\n        dp.build(pad_to_200(scored[k].second));\n\n        // quick greedy suffix improvement (cheap, stable)\n        double sweepEnd = min(endTime, timer.elapsed() + 0.06);\n        greedySuffixImprove(dp, 80, timer, sweepEnd);\n\n        // validate after sweep\n        {\n            double scFull = fullEval.eval(dp.seq);\n            if (scFull > globalBestFull) { globalBestFull = scFull; globalBestStr = dp.seq; }\n        }\n\n        XorShift localRng(splitmix64(seed ^ (uint64_t)k ^ 0x123456789abcdef0ULL));\n        SA_fastDelta(dp, fullEval, globalBestFull, globalBestStr, timer, endTime, localRng);\n    }\n\n    cout << pad_to_200(globalBestStr) << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TILES = N * N;\nstatic constexpr int PORTS = TILES * 4;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU64() % (uint64_t)(hi - lo + 1));\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct EvalResult {\n    long long baseScore;     // L1*L2 (true score if >=2 loops else 0)\n    int L1, L2;\n    int loopCount;\n    int compCount;\n    int matchedEdges;        // active-active borders\n    int openEnds;            // endpoints with deg==1\n    int largestCompLen;      // max(compSize/2) over all components (loops or paths)\n    long long sumCompLenSq;  // sum (compLen^2) over all components\n    double energy;           // SA energy\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Input\n    vector<uint8_t> initState(TILES);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) initState[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    // Rotation map (90deg CCW)\n    // 0->1->2->3->0, 4<->5, 6<->7\n    array<uint8_t, 8> rot1 = {1,2,3,0,5,4,7,6};\n    uint8_t rotStep[8][4];\n    for (int t = 0; t < 8; t++) {\n        rotStep[t][0] = (uint8_t)t;\n        rotStep[t][1] = rot1[t];\n        rotStep[t][2] = rot1[rotStep[t][1]];\n        rotStep[t][3] = rot1[rotStep[t][2]];\n    }\n\n    // side masks (L,U,R,D) bits 0..3, and internal pairings\n    uint8_t sideMask[8];\n    uint8_t pairCnt[8];\n    uint8_t pairs[8][2][2]; // up to 2 segments (each a pair of sides)\n\n    auto set1 = [&](int t, int a, int b, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 1;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = pairs[t][1][1] = 255;\n    };\n    auto set2 = [&](int t, int a, int b, int c, int d, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 2;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = (uint8_t)c;\n        pairs[t][1][1] = (uint8_t)d;\n    };\n\n    // 0: L-U\n    set1(0, 0, 1, (1u<<0) | (1u<<1));\n    // 1: L-D\n    set1(1, 0, 3, (1u<<0) | (1u<<3));\n    // 2: R-D\n    set1(2, 2, 3, (1u<<2) | (1u<<3));\n    // 3: U-R\n    set1(3, 1, 2, (1u<<1) | (1u<<2));\n    // 4: (L-U) and (R-D)\n    set2(4, 0, 1, 2, 3, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 5: (L-D) and (U-R)\n    set2(5, 0, 3, 1, 2, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 6: L-R\n    set1(6, 0, 2, (1u<<0) | (1u<<2));\n    // 7: U-D\n    set1(7, 1, 3, (1u<<1) | (1u<<3));\n\n    auto applyFromInit = [&](int idx, uint8_t r) -> uint8_t {\n        return rotStep[initState[idx]][r & 3];\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift64 rng(seed);\n\n    // Current state\n    vector<uint8_t> curRot(TILES, 0);\n    vector<uint8_t> curState(TILES, 0);\n    vector<uint8_t> curMask(TILES, 0);\n\n    // indices of 4/5 tiles (pairing-changing tiles)\n    vector<int> pairTiles;\n    pairTiles.reserve(TILES);\n    for (int p = 0; p < TILES; p++) {\n        if (initState[p] == 4 || initState[p] == 5) pairTiles.push_back(p);\n    }\n\n    // Random init\n    for (int p = 0; p < TILES; p++) {\n        uint8_t r = (uint8_t)rng.nextInt(0, 3);\n        curRot[p] = r;\n        curState[p] = applyFromInit(p, r);\n        curMask[p] = sideMask[curState[p]];\n    }\n\n    // Greedy init:\n    // - reward active-active matches\n    // - penalize mismatch\n    // - penalize boundary leaks\n    // - add pairing potential for 4/5 tiles (and generally for any tile's internal pairs)\n    auto cont = [&](int p, int side) -> int {\n        int i = p / N, j = p % N;\n        if (side == 0) { // L\n            if (j == 0) return 0;\n            return (curMask[p - 1] & (1u << 2)) ? 1 : 0;\n        } else if (side == 1) { // U\n            if (i == 0) return 0;\n            return (curMask[p - N] & (1u << 3)) ? 1 : 0;\n        } else if (side == 2) { // R\n            if (j == N - 1) return 0;\n            return (curMask[p + 1] & (1u << 0)) ? 1 : 0;\n        } else { // D\n            if (i == N - 1) return 0;\n            return (curMask[p + N] & (1u << 1)) ? 1 : 0;\n        }\n    };\n\n    auto greedyLocalScore = [&](int p, uint8_t stCand) -> int {\n        int i = p / N, j = p % N;\n        uint8_t mCand = sideMask[stCand];\n\n        int sc = 0;\n        // border match score: only active-active is good\n        auto evalSide = [&](int side, int ni, int nj, int oppSide) {\n            bool a = (mCand >> side) & 1;\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (a) sc -= 6; // boundary leak\n                return;\n            }\n            int q = ni * N + nj;\n            bool b = (curMask[q] >> oppSide) & 1;\n            if (a && b) sc += 5;\n            else if (a != b) sc -= 5;\n            // both inactive: 0\n        };\n\n        evalSide(0, i, j - 1, 2);\n        evalSide(1, i - 1, j, 3);\n        evalSide(2, i, j + 1, 0);\n        evalSide(3, i + 1, j, 1);\n\n        // internal pairing potential:\n        // prefer pairing that connects \"continuable\" sides together.\n        int c[4] = { cont(p,0), cont(p,1), cont(p,2), cont(p,3) };\n        int ps = 0;\n        for (int k = 0; k < pairCnt[stCand]; k++) {\n            int a = pairs[stCand][k][0], b = pairs[stCand][k][1];\n            ps += c[a] * c[b];\n        }\n        sc += ps * 3;\n\n        return sc;\n    };\n\n    vector<int> order(TILES);\n    iota(order.begin(), order.end(), 0);\n\n    for (int sweep = 0; sweep < 8; sweep++) {\n        for (int i = TILES - 1; i > 0; i--) {\n            int j = (int)(rng.nextU64() % (uint64_t)(i + 1));\n            swap(order[i], order[j]);\n        }\n        for (int idx = 0; idx < TILES; idx++) {\n            int p = order[idx];\n            int bestSc = INT_MIN;\n            uint8_t bestDelta = 0;\n            uint8_t base = curState[p];\n            for (uint8_t dlt = 0; dlt < 4; dlt++) {\n                uint8_t stCand = rotStep[base][dlt];\n                int sc = greedyLocalScore(p, stCand);\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestDelta = dlt;\n                }\n            }\n            if (bestDelta != 0) {\n                curRot[p] = (uint8_t)((curRot[p] + bestDelta) & 3);\n                curState[p] = rotStep[curState[p]][bestDelta];\n                curMask[p] = sideMask[curState[p]];\n            }\n        }\n    }\n\n    // Evaluation buffers\n    static int degArr[PORTS];\n    static int nb1[PORTS];\n    static int nb2[PORTS];\n    static uint8_t vis[PORTS];\n    static int stackBuf[PORTS];\n\n    auto addEdge = [&](int u, int v) {\n        int du = degArr[u]++;\n        if (du == 0) nb1[u] = v;\n        else nb2[u] = v;\n\n        int dv = degArr[v]++;\n        if (dv == 0) nb1[v] = u;\n        else nb2[v] = u;\n    };\n\n    auto evaluate = [&]() -> EvalResult {\n        memset(degArr, 0, sizeof(degArr));\n        memset(nb1, 0xFF, sizeof(nb1)); // -1\n        memset(nb2, 0xFF, sizeof(nb2));\n        memset(vis, 0, sizeof(vis));\n\n        // internal edges\n        for (int p = 0; p < TILES; p++) {\n            int base = p * 4;\n            uint8_t st = curState[p];\n            for (int k = 0; k < pairCnt[st]; k++) {\n                int a = pairs[st][k][0];\n                int b = pairs[st][k][1];\n                addEdge(base + a, base + b);\n            }\n        }\n\n        // external edges\n        int matchedEdges = 0;\n        // horizontal\n        for (int i = 0; i < N; i++) {\n            int row = i * N;\n            for (int j = 0; j < N - 1; j++) {\n                int p = row + j;\n                int q = p + 1;\n                if ((curMask[p] & (1u << 2)) && (curMask[q] & (1u << 0))) {\n                    addEdge(p * 4 + 2, q * 4 + 0);\n                    matchedEdges++;\n                }\n            }\n        }\n        // vertical\n        for (int i = 0; i < N - 1; i++) {\n            int row = i * N;\n            int row2 = (i + 1) * N;\n            for (int j = 0; j < N; j++) {\n                int p = row + j;\n                int q = row2 + j;\n                if ((curMask[p] & (1u << 3)) && (curMask[q] & (1u << 1))) {\n                    addEdge(p * 4 + 3, q * 4 + 1);\n                    matchedEdges++;\n                }\n            }\n        }\n\n        int openEnds = 0;\n        for (int u = 0; u < PORTS; u++) if (degArr[u] == 1) openEnds++;\n\n        int L1 = 0, L2 = 0;\n        int loopCount = 0;\n        int compCount = 0;\n        int largestCompLen = 0;\n        long long sumCompLenSq = 0;\n\n        for (int s = 0; s < PORTS; s++) {\n            if (degArr[s] == 0 || vis[s]) continue;\n            compCount++;\n\n            int top = 0;\n            stackBuf[top++] = s;\n            vis[s] = 1;\n\n            int compSize = 0;\n            bool isCycle = true;\n\n            while (top) {\n                int x = stackBuf[--top];\n                compSize++;\n                if (degArr[x] != 2) isCycle = false;\n\n                int a = nb1[x], b = nb2[x];\n                if (a != -1 && !vis[a]) { vis[a] = 1; stackBuf[top++] = a; }\n                if (b != -1 && !vis[b]) { vis[b] = 1; stackBuf[top++] = b; }\n            }\n\n            int compLen = compSize / 2; // moves\n            largestCompLen = max(largestCompLen, compLen);\n            sumCompLenSq += 1LL * compLen * compLen;\n\n            if (isCycle) {\n                loopCount++;\n                if (compLen > L1) { L2 = L1; L1 = compLen; }\n                else if (compLen > L2) { L2 = compLen; }\n            }\n        }\n\n        long long base = (loopCount >= 2) ? 1LL * L1 * L2 : 0LL;\n\n        // Energy:\n        // - if >=2 loops exist: focus on product, but discourage too many loops\n        // - if <2: grow large components (easy to close later) and reduce fragmentation\n        double energy;\n        if (loopCount >= 2) {\n            energy = base * 200.0\n                   + (L1 + L2) * 50.0\n                   + largestCompLen * 5.0\n                   + sumCompLenSq * 0.002\n                   - openEnds * 2.0\n                   - max(0, loopCount - 2) * 500.0;\n        } else if (loopCount == 1) {\n            energy = L1 * 60.0\n                   + largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 6000.0;\n        } else {\n            energy = largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 12000.0;\n        }\n\n        return EvalResult{base, L1, L2, loopCount, compCount, matchedEdges, openEnds,\n                          largestCompLen, sumCompLenSq, energy};\n    };\n\n    EvalResult curEval = evaluate();\n    long long bestBase = curEval.baseScore;\n    int bestTie = curEval.L1 + curEval.L2;\n    vector<uint8_t> bestRot = curRot;\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.93;\n\n    // SA temperature (energy scale is now larger)\n    const double T0 = 12000.0;\n    const double T1 = 150.0;\n\n    struct Backup {\n        int p;\n        uint8_t rot, st, mask;\n    };\n\n    auto applyDelta = [&](int p, uint8_t delta) {\n        if ((delta & 3) == 0) return;\n        curRot[p] = (uint8_t)((curRot[p] + delta) & 3);\n        curState[p] = rotStep[curState[p]][delta & 3];\n        curMask[p] = sideMask[curState[p]];\n    };\n\n    long long iter = 0;\n    while (true) {\n        iter++;\n        if ((iter & 1023) == 0) {\n            double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (sec >= TL) break;\n        }\n\n        // move type\n        int r = (int)(rng.nextU64() % 1000);\n\n        vector<int> ps;\n        vector<uint8_t> deltas;\n\n        if (r < 850) {\n            // single tile (bias to 4/5 tiles sometimes)\n            int p;\n            if (!pairTiles.empty() && rng.nextDouble() < 0.45) {\n                p = pairTiles[rng.nextInt(0, (int)pairTiles.size() - 1)];\n            } else {\n                p = (int)(rng.nextU64() % TILES);\n            }\n            uint8_t delta = (uint8_t)(1 + (rng.nextU32() % 3));\n            uint8_t newS = rotStep[curState[p]][delta];\n            if (newS == curState[p]) { delta = 1; }\n            ps = {p};\n            deltas = {delta};\n        } else if (r < 950) {\n            // 2x2 move\n            int i = rng.nextInt(0, N - 2);\n            int j = rng.nextInt(0, N - 2);\n            int p0 = i * N + j;\n            ps = {p0, p0 + 1, p0 + N, p0 + N + 1};\n            deltas.resize(4);\n            int nonzero = 0;\n            for (int k = 0; k < 4; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,3)] = 1;\n        } else {\n            // 1x3 or 3x1 move\n            bool horiz = (rng.nextU32() & 1);\n            if (horiz) {\n                int i = rng.nextInt(0, N - 1);\n                int j = rng.nextInt(0, N - 3);\n                int p0 = i * N + j;\n                ps = {p0, p0 + 1, p0 + 2};\n            } else {\n                int i = rng.nextInt(0, N - 3);\n                int j = rng.nextInt(0, N - 1);\n                int p0 = i * N + j;\n                ps = {p0, p0 + N, p0 + 2 * N};\n            }\n            deltas.resize(3);\n            int nonzero = 0;\n            for (int k = 0; k < 3; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,2)] = 1;\n        }\n\n        // backup and apply\n        vector<Backup> backups;\n        backups.reserve(ps.size());\n        for (int idx = 0; idx < (int)ps.size(); idx++) {\n            int p = ps[idx];\n            backups.push_back(Backup{p, curRot[p], curState[p], curMask[p]});\n            applyDelta(p, deltas[idx]);\n        }\n\n        EvalResult nxtEval = evaluate();\n\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = min(1.0, sec / TL);\n        double Temp = T0 * pow(T1 / T0, t);\n\n        double diff = nxtEval.energy - curEval.energy;\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else {\n            double prob = exp(diff / Temp);\n            accept = (rng.nextDouble() < prob);\n        }\n\n        if (accept) {\n            curEval = nxtEval;\n            // best by true score, tie by L1+L2\n            int tie = nxtEval.L1 + nxtEval.L2;\n            if (nxtEval.baseScore > bestBase || (nxtEval.baseScore == bestBase && tie > bestTie)) {\n                bestBase = nxtEval.baseScore;\n                bestTie = tie;\n                bestRot = curRot;\n            }\n        } else {\n            // revert\n            for (auto &b : backups) {\n                curRot[b.p] = b.rot;\n                curState[b.p] = b.st;\n                curMask[b.p] = b.mask;\n            }\n        }\n    }\n\n    // output best\n    string out;\n    out.reserve(TILES);\n    for (int p = 0; p < TILES; p++) out.push_back(char('0' + (bestRot[p] & 3)));\n    cout << out << \"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline int hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nstruct Metrics {\n    int largestTree = 0;\n    int bestAlmost = 0;\n    int edgesTotal = 0;\n    int cycleSurplus = 0;\n    int cyclicLargest = 0;\n    int borderOut = 0;\n    int mismatch = 0;\n    int treeMass = 0; // sum of squares of tree component sizes\n    long long obj = 0;\n};\n\nstruct UF {\n    int n;\n    int p[110], sz[110];\n    void init(int n_) {\n        n = n_;\n        for (int i = 0; i < n; i++) { p[i] = i; sz[i] = 1; }\n    }\n    int find(int a) {\n        while (p[a] != a) {\n            p[a] = p[p[a]];\n            a = p[a];\n        }\n        return a;\n    }\n    void unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return;\n        if (sz[a] < sz[b]) swap(a,b);\n        p[b] = a;\n        sz[a] += sz[b];\n    }\n};\n\nstruct Solver {\n    int N, T;\n    int NN;\n    int V; // N*N - 1\n    vector<uint8_t> init;\n    int initBlank = -1;\n\n    // blank move directions: U D L R\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char dch[4] = {'U','D','L','R'};\n    const int opp[4] = {1,0,3,2};\n\n    // precomputed legal moves from each blank cell\n    int moveCnt[110];\n    int moveList[110][4];\n\n    // edge storage for evaluation (max 2*N*(N-1) <= 180 for N=10)\n    int eU[256], eV[256];\n\n    void precompute_moves() {\n        for (int pos = 0; pos < NN; pos++) {\n            int r = pos / N, c = pos % N;\n            int k = 0;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    moveList[pos][k++] = d;\n                }\n            }\n            moveCnt[pos] = k;\n        }\n    }\n\n    inline void do_move_inplace(vector<uint8_t>& b, int& blank, int d) const {\n        int r = blank / N, c = blank % N;\n        int nb = (r + dr[d]) * N + (c + dc[d]);\n        swap(b[blank], b[nb]);\n        blank = nb;\n    }\n\n    Metrics evaluate(const vector<uint8_t>& b) {\n        UF uf;\n        uf.init(NN);\n\n        int eidx = 0;\n        int edgesTotal = 0;\n        int borderOut = 0;\n        int mismatch = 0;\n\n        // border penalties + adjacency processing (also union matches)\n        for (int r = 0; r < N; r++) {\n            int base = r * N;\n            for (int c = 0; c < N; c++) {\n                int id = base + c;\n                uint8_t t = b[id];\n                if (t == 0) continue;\n\n                if (r == 0 && (t & 2)) borderOut++;\n                if (r == N-1 && (t & 8)) borderOut++;\n                if (c == 0 && (t & 1)) borderOut++;\n                if (c == N-1 && (t & 4)) borderOut++;\n\n                // right neighbor\n                if (c + 1 < N) {\n                    int id2 = id + 1;\n                    uint8_t t2 = b[id2];\n                    bool ar = (t & 4);\n                    bool bl = (t2 & 1);\n                    // mismatch counts line-ends that do not match\n                    if (t != 0 && ar && !(t2 != 0 && bl)) mismatch++;\n                    if (t2 != 0 && bl && !(t != 0 && ar)) mismatch++;\n                    if (t2 != 0 && ar && bl) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n                // down neighbor\n                if (r + 1 < N) {\n                    int id2 = id + N;\n                    uint8_t t2 = b[id2];\n                    bool ad = (t & 8);\n                    bool bu = (t2 & 2);\n                    if (t != 0 && ad && !(t2 != 0 && bu)) mismatch++;\n                    if (t2 != 0 && bu && !(t != 0 && ad)) mismatch++;\n                    if (t2 != 0 && ad && bu) {\n                        uf.unite(id, id2);\n                        eU[eidx] = id; eV[eidx] = id2; eidx++;\n                        edgesTotal++;\n                    }\n                }\n            }\n        }\n\n        static int vcnt[110];\n        static int ecnt[110];\n        for (int i = 0; i < NN; i++) { vcnt[i] = 0; ecnt[i] = 0; }\n\n        for (int i = 0; i < NN; i++) {\n            if (b[i] == 0) continue;\n            vcnt[uf.find(i)]++;\n        }\n        for (int k = 0; k < eidx; k++) {\n            int root = uf.find(eU[k]);\n            ecnt[root]++;\n        }\n\n        Metrics m;\n        m.edgesTotal = edgesTotal;\n        m.borderOut = borderOut;\n        m.mismatch = mismatch;\n\n        int largestTree = 0;\n        int bestAlmost = 0;\n        int cycleSurplus = 0;\n        int cyclicLargest = 0;\n        long long treeMass = 0;\n\n        for (int i = 0; i < NN; i++) {\n            int Vc = vcnt[i];\n            if (Vc == 0) continue;\n            int Ec = ecnt[i];\n            int extra = max(0, Ec - (Vc - 1));\n            cycleSurplus += extra;\n            if (extra > 0) cyclicLargest = max(cyclicLargest, Vc);\n\n            if (extra == 0) {\n                largestTree = max(largestTree, Vc);\n                treeMass += 1LL * Vc * Vc;\n            }\n            // closeness-to-tree potential (penalize extra edges strongly)\n            bestAlmost = max(bestAlmost, Vc - 10 * extra);\n        }\n\n        m.largestTree = largestTree;\n        m.bestAlmost = bestAlmost;\n        m.cycleSurplus = cycleSurplus;\n        m.cyclicLargest = cyclicLargest;\n        m.treeMass = (int)min<long long>(treeMass, INT_MAX);\n\n        // Objective: prioritize real largest-tree size, then push away from cycles,\n        // and encourage border/port consistency.\n        long long obj = 0;\n        obj += 1000000000LL * m.largestTree;          // primary\n        obj += 20000000LL   * m.bestAlmost;           // secondary\n        obj += 5000LL       * m.treeMass;             // encourage big forests\n        obj += 200000LL     * m.edgesTotal;           // matched edges help (but not at all costs)\n        obj -= 50000000LL   * m.cyclicLargest;        // big cyclic component is disastrous\n        obj -= 20000000LL   * m.cycleSurplus;         // cycles are bad\n        obj -= 500000LL     * m.borderOut;            // outward ports cannot be matched\n        obj -= 20000LL      * m.mismatch;             // unmatched ends hurt\n\n        m.obj = obj;\n        return m;\n    }\n\n    struct RunResult {\n        string path;\n        int bestS;\n        int bestLen;\n    };\n\n    RunResult run_once(XorShift64& rng, double time_frac) {\n        vector<uint8_t> b = init;\n        int blank = initBlank;\n\n        Metrics cur = evaluate(b);\n        int bestS = cur.largestTree;\n        int bestLen = 0;\n        string path;\n        path.reserve(T);\n\n        int prevd = -1;\n\n        // exploration schedule (vary per run)\n        double eps0 = 0.40 - 0.15 * time_frac; // earlier runs explore more\n        double eps1 = 0.05;\n        // randomize slightly per run\n        eps0 *= (0.85 + 0.30 * rng.next_double());\n        eps1 *= (0.85 + 0.30 * rng.next_double());\n        eps0 = min(0.65, max(0.05, eps0));\n        eps1 = min(0.20, max(0.01, eps1));\n\n        for (int step = 0; step < T; step++) {\n            // build candidate moves from precomputed list\n            int cand[4], cc = 0;\n            int mc = moveCnt[blank];\n            for (int i = 0; i < mc; i++) cand[cc++] = moveList[blank][i];\n\n            // avoid immediate reverse most of the time (but not always)\n            if (prevd != -1 && cc >= 2 && rng.next_double() < 0.90) {\n                int rev = opp[prevd];\n                int nc = 0;\n                for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                if (nc >= 1) cc = nc;\n            }\n\n            struct CandInfo { int d; Metrics m1; long long score; };\n            CandInfo infos[4];\n\n            // evaluate each candidate (1-step)\n            for (int i = 0; i < cc; i++) {\n                int d = cand[i];\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d);\n                Metrics m1 = evaluate(b);\n                // revert\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                infos[i] = {d, m1, m1.obj};\n            }\n\n            // take top-2 by score and do 2-step lookahead on them\n            int order[4];\n            iota(order, order + cc, 0);\n            sort(order, order + cc, [&](int a, int b) {\n                return infos[a].score > infos[b].score;\n            });\n\n            int topk = min(2, cc);\n            for (int t = 0; t < topk; t++) {\n                int idx = order[t];\n                int d1 = infos[idx].d;\n\n                int savedBlank = blank;\n                do_move_inplace(b, blank, d1);\n\n                // enumerate next moves excluding immediate reverse of d1\n                long long best2 = LLONG_MIN;\n                int mc2 = moveCnt[blank];\n                for (int j = 0; j < mc2; j++) {\n                    int d2 = moveList[blank][j];\n                    if (d2 == opp[d1] && mc2 >= 2) continue;\n                    int savedBlank2 = blank;\n                    do_move_inplace(b, blank, d2);\n                    Metrics m2 = evaluate(b);\n                    best2 = max(best2, m2.obj);\n                    // revert\n                    swap(b[savedBlank2], b[blank]);\n                    blank = savedBlank2;\n                }\n\n                // revert state1\n                swap(b[savedBlank], b[blank]);\n                blank = savedBlank;\n\n                if (best2 != LLONG_MIN) {\n                    // small influence of lookahead\n                    infos[idx].score = infos[idx].m1.obj + best2 / 10;\n                }\n            }\n\n            // epsilon-greedy choice\n            double eps = eps0 + (eps1 - eps0) * (double)step / max(1, T - 1);\n            int chosen = 0;\n            if (rng.next_double() < eps) {\n                chosen = rng.next_int(0, cc - 1);\n            } else {\n                long long bestScore = LLONG_MIN;\n                for (int i = 0; i < cc; i++) {\n                    // small random tie-break\n                    long long s = infos[i].score + (long long)(rng.next_u64() & 1023ULL);\n                    if (s > bestScore) {\n                        bestScore = s;\n                        chosen = i;\n                    }\n                }\n            }\n\n            int d = infos[chosen].d;\n            do_move_inplace(b, blank, d);\n            path.push_back(dch[d]);\n            prevd = d;\n            cur = infos[chosen].m1;\n\n            int S = cur.largestTree;\n            int len = step + 1;\n            if (S > bestS) {\n                bestS = S;\n                bestLen = len;\n            } else if (S == bestS) {\n                // if perfect, prefer shorter; otherwise shorter is fine too\n                if (len < bestLen) bestLen = len;\n            }\n\n            if (bestS == V) {\n                // first time reaching perfect is already shortest in this run\n                bestLen = len;\n                break;\n            }\n        }\n\n        RunResult rr;\n        rr.bestS = bestS;\n        rr.bestLen = bestLen;\n        rr.path = path.substr(0, bestLen);\n        return rr;\n    }\n\n    string solve() {\n        NN = N * N;\n        V = NN - 1;\n        precompute_moves();\n\n        Metrics m0 = evaluate(init);\n        int globalBestS = m0.largestTree;\n        int globalBestLen = 0;\n        string globalBest = \"\";\n\n        auto st = chrono::high_resolution_clock::now();\n        const double TL = 2.85;\n\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        while (true) {\n            auto now = chrono::high_resolution_clock::now();\n            double elapsed = chrono::duration<double>(now - st).count();\n            if (elapsed >= TL) break;\n\n            double frac = elapsed / TL;\n            RunResult rr = run_once(rng, frac);\n\n            if (rr.bestS > globalBestS) {\n                globalBestS = rr.bestS;\n                globalBestLen = rr.bestLen;\n                globalBest = rr.path;\n            } else if (rr.bestS == globalBestS) {\n                // if perfect, shorter is strictly better; otherwise doesn't affect score, but keep shorter\n                if (rr.bestLen < globalBestLen) {\n                    globalBestLen = rr.bestLen;\n                    globalBest = rr.path;\n                }\n            }\n\n            if (globalBestS == V && globalBestLen == 0) break;\n        }\n\n        if ((int)globalBest.size() > T) globalBest.resize(T);\n        return globalBest;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.T;\n    int N = solver.N;\n\n    solver.init.assign(N * N, 0);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) {\n            int v = hexval(s[j]);\n            solver.init[i * N + j] = (uint8_t)v;\n            if (v == 0) solver.initBlank = i * N + j;\n        }\n    }\n\n    string ans = solver.solve();\n    cout << ans << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int R = 10000;\nstatic constexpr long long LEN = 100000000LL;     // 1e8\nstatic constexpr double U_INACTIVE = R + 4000.0;  // |u| > R => line doesn't intersect the cake\n\n// ---------------- RNG ----------------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline double uniform01() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double uniform(double lo, double hi) { return lo + (hi - lo) * uniform01(); }\n    inline int uniformInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// ---------------- Geometry / signature ----------------\nstruct Point { int x, y; };\n\nstruct Line {\n    double theta; // [0, pi)\n    double u;     // signed distance along normal\n    long long px, py, qx, qy; // endpoints\n};\n\nstruct Key {\n    uint64_t lo = 0, hi = 0; // up to 128 lines\n    bool operator==(Key const& o) const noexcept { return lo == o.lo && hi == o.hi; }\n};\n\nstruct KeyHash {\n    size_t operator()(Key const& k) const noexcept {\n        uint64_t h = k.lo ^ splitmix64(k.hi + 0x9e3779b97f4a7c15ULL);\n        return (size_t)splitmix64(h);\n    }\n};\n\nstatic inline int getBit(const Key& k, int idx) {\n    if (idx < 64) return (int)((k.lo >> idx) & 1ULL);\n    return (int)((k.hi >> (idx - 64)) & 1ULL);\n}\nstatic inline void setBit(Key& k, int idx) {\n    if (idx < 64) k.lo |= (1ULL << idx);\n    else k.hi |= (1ULL << (idx - 64));\n}\nstatic inline void toggleBit(Key& k, int idx) {\n    if (idx < 64) k.lo ^= (1ULL << idx);\n    else k.hi ^= (1ULL << (idx - 64));\n}\n\nstatic inline double wrapTheta(double th) {\n    const double PI = acos(-1.0);\n    while (th < 0) th += PI;\n    while (th >= PI) th -= PI;\n    return th;\n}\n\nstatic inline Line buildLine(double theta, double u) {\n    double cs = cos(theta), sn = sin(theta);\n    double tx = -sn, ty = cs;\n    double cx = u * cs, cy = u * sn;\n\n    long double px = (long double)cx + (long double)LEN * (long double)tx;\n    long double py = (long double)cy + (long double)LEN * (long double)ty;\n    long double qx = (long double)cx - (long double)LEN * (long double)tx;\n    long double qy = (long double)cy - (long double)LEN * (long double)ty;\n\n    Line L;\n    L.theta = theta;\n    L.u = u;\n    L.px = llround(px);\n    L.py = llround(py);\n    L.qx = llround(qx);\n    L.qy = llround(qy);\n    if (L.px == L.qx && L.py == L.qy) L.qx += 1;\n    return L;\n}\n\n// exact side test by integer cross product\n// 1 if cross>0, 0 if cross<0, -1 if cross==0 (strawberry disappears)\nstatic inline int sideBit(const Line& L, const Point& p) {\n    __int128 dx = (__int128)L.qx - (__int128)L.px;\n    __int128 dy = (__int128)L.qy - (__int128)L.py;\n    __int128 ax = (__int128)p.x - (__int128)L.px;\n    __int128 ay = (__int128)p.y - (__int128)L.py;\n    __int128 cr = dx * ay - dy * ax;\n    if (cr > 0) return 1;\n    if (cr < 0) return 0;\n    return -1;\n}\n\nstatic inline bool isInactive(const Line& L) { return fabs(L.u) > (double)R + 1.0; }\n\n// ---------------- State ----------------\nstruct State {\n    int N = 0;\n    int L = 0;\n    vector<Point> pts;\n    vector<Line> lines;\n    vector<Key> sig;\n    boost::unordered_flat_map<Key, int, KeyHash> mp;\n\n    array<int, 11> a{};\n    array<int, 11> b{}; // pieces with exactly d (1..10)\n    long long excess = 0;   // sum max(0,c-10)\n    long long excess2 = 0;  // sum (max(0,c-10))^2\n    int goodPieces = 0;     // regions with 1..10\n\n    void clearCounts() {\n        mp.clear();\n        b.fill(0);\n        excess = excess2 = 0;\n        goodPieces = 0;\n    }\n\n    static inline long long ex(int c) { return (c <= 10) ? 0LL : (long long)(c - 10); }\n    static inline long long ex2(int c) {\n        if (c <= 10) return 0LL;\n        long long e = (long long)(c - 10);\n        return e * e;\n    }\n\n    inline void updateMetrics(int oldC, int newC) {\n        if (1 <= oldC && oldC <= 10) { b[oldC]--; goodPieces--; }\n        if (1 <= newC && newC <= 10) { b[newC]++; goodPieces++; }\n        excess -= ex(oldC);  excess += ex(newC);\n        excess2 -= ex2(oldC); excess2 += ex2(newC);\n    }\n\n    inline void incRegion(const Key& k) {\n        auto it = mp.find(k);\n        if (it == mp.end()) {\n            updateMetrics(0, 1);\n            mp.emplace(k, 1);\n        } else {\n            int oldC = it->second, newC = oldC + 1;\n            updateMetrics(oldC, newC);\n            it->second = newC;\n        }\n    }\n    inline void decRegion(const Key& k) {\n        auto it = mp.find(k);\n        int oldC = it->second, newC = oldC - 1;\n        updateMetrics(oldC, newC);\n        if (newC == 0) mp.erase(it);\n        else it->second = newC;\n    }\n\n    inline int distributed() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], b[d]);\n        return s;\n    }\n\n    inline long long deficit2() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - b[d]);\n            s += 1LL * def * def;\n        }\n        return s;\n    }\n\n    inline long long overWeighted() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int over = max(0, b[d] - a[d]);\n            long long w = (12 - d);\n            s += 1LL * over * w * w;\n        }\n        return s;\n    }\n\n    inline long long secondaryScore() const {\n        long long def2 = deficit2();\n        long long ovW = overWeighted();\n        long long S = 0;\n        S += 1LL * goodPieces * 80;\n        S -= 1LL * excess2 * 3;\n        S -= 1LL * excess * 160;\n        S -= 1LL * def2 * 780;\n        S -= 1LL * ovW * 115;\n        return S;\n    }\n\n    bool buildInitialSignatures() {\n        sig.assign(N, Key{0, 0});\n        clearCounts();\n        mp.reserve((size_t)N * 2 + 64);\n\n        for (int i = 0; i < L; i++) {\n            for (int j = 0; j < N; j++) {\n                int sb = sideBit(lines[i], pts[j]);\n                if (sb == -1) return false;\n                if (sb == 1) setBit(sig[j], i);\n            }\n        }\n        for (int j = 0; j < N; j++) incRegion(sig[j]);\n        return true;\n    }\n\n    // replace one line; rollback on invalid\n    bool applyReplaceLine(int idx, const Line& newLine,\n                          vector<int>& changedIdx, vector<Key>& oldSig) {\n        changedIdx.clear();\n        oldSig.clear();\n        changedIdx.reserve(256);\n        oldSig.reserve(256);\n\n        for (int j = 0; j < N; j++) {\n            int nb = sideBit(newLine, pts[j]);\n            if (nb == -1) {\n                for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n                    int pj = changedIdx[t];\n                    Key os = oldSig[t];\n                    Key cs = sig[pj];\n                    decRegion(cs);\n                    incRegion(os);\n                    sig[pj] = os;\n                }\n                changedIdx.clear();\n                oldSig.clear();\n                return false;\n            }\n            int ob = getBit(sig[j], idx);\n            if (nb == ob) continue;\n\n            changedIdx.push_back(j);\n            oldSig.push_back(sig[j]);\n\n            Key ns = sig[j];\n            toggleBit(ns, idx);\n            decRegion(sig[j]);\n            incRegion(ns);\n            sig[j] = ns;\n        }\n        return true;\n    }\n\n    void rollbackReplaceLine(const vector<int>& changedIdx, const vector<Key>& oldSig) {\n        for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n            int j = changedIdx[t];\n            Key os = oldSig[t];\n            Key cs = sig[j];\n            decRegion(cs);\n            incRegion(os);\n            sig[j] = os;\n        }\n    }\n};\n\n// ---------------- Timer ----------------\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// ---------------- Helpers ----------------\nstatic Line randomActiveLineAnchored(RNG& rng, const vector<Point>& pts, double theta, double noiseU) {\n    double cs = cos(theta), sn = sin(theta);\n    const Point& p = pts[rng.uniformInt(0, (int)pts.size() - 1)];\n    double proj = cs * (double)p.x + sn * (double)p.y;\n    double u = proj + rng.uniform(-noiseU, noiseU);\n    double lim = R * 0.98;\n    u = max(-lim, min(lim, u));\n    return buildLine(theta, u);\n}\n\n// choose sign of inactive u to match as many current bits as possible (fewer flips -> faster / gentler)\nstatic Line inactiveLineMatched(const State& st, int idx, RNG& rng) {\n    double theta = st.lines[idx].theta;\n    Line Lpos = buildLine(theta, +U_INACTIVE);\n    Line Lneg = buildLine(theta, -U_INACTIVE);\n\n    int matchPos = 0, matchNeg = 0;\n    int samples = min(st.N, 80);\n    for (int t = 0; t < samples; t++) {\n        int j = (st.N == samples) ? t : rng.uniformInt(0, st.N - 1);\n        int ob = getBit(st.sig[j], idx);\n        int nbp = sideBit(Lpos, st.pts[j]);\n        int nbn = sideBit(Lneg, st.pts[j]);\n        if (nbp == ob) matchPos++;\n        if (nbn == ob) matchNeg++;\n    }\n    return (matchPos >= matchNeg) ? Lpos : Lneg;\n}\n\nstatic int nearestLineIndex(const vector<Line>& lines, const Point& p) {\n    int best = 0;\n    double bestAbs = 1e100;\n    for (int i = 0; i < (int)lines.size(); i++) {\n        double cs = cos(lines[i].theta), sn = sin(lines[i].theta);\n        double dist = cs * (double)p.x + sn * (double)p.y - lines[i].u;\n        double ad = fabs(dist);\n        if (ad < bestAbs) { bestAbs = ad; best = i; }\n    }\n    return best;\n}\n\nstatic int pickInactiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (isInactive(lines[i])) return i;\n    }\n    for (int i = 0; i < L; i++) if (isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\nstatic int pickActiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (!isInactive(lines[i])) return i;\n    }\n    for (int i = 0; i < L; i++) if (!isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\n// Generate a quantile split line for a given region (key) and target size d.\n// Returns false if region too small.\nstatic bool generateQuantileSplit(const State& st, const Key& key, int regionSize, int targetD,\n                                  RNG& rng, Line& outLine) {\n    if (regionSize <= targetD || regionSize < 6) return false;\n\n    // collect region members\n    vector<int> idxs;\n    idxs.reserve(regionSize);\n    for (int j = 0; j < st.N; j++) if (st.sig[j] == key) idxs.push_back(j);\n    if ((int)idxs.size() < 6) return false;\n\n    // sample up to 220 points to reduce cost / noise\n    int M = min<int>(220, (int)idxs.size());\n    if ((int)idxs.size() > M) {\n        for (int t = 0; t < M; t++) {\n            int r = rng.uniformInt(t, (int)idxs.size() - 1);\n            swap(idxs[t], idxs[r]);\n        }\n        idxs.resize(M);\n    }\n\n    const double PI = acos(-1.0);\n    int ANG = 12;\n    double bestTheta = rng.uniform(0.0, PI);\n    double bestU = 0.0;\n    double bestGap = -1.0;\n\n    // desired fraction\n    double frac = (double)targetD / (double)regionSize;\n    int kpos = (int)llround(frac * (double)(M - 1));\n    kpos = max(1, min(M - 1, kpos));\n\n    vector<double> proj;\n    proj.reserve(M);\n\n    for (int t = 0; t < ANG; t++) {\n        double theta = rng.uniform(0.0, PI);\n        double cs = cos(theta), sn = sin(theta);\n\n        proj.clear();\n        for (int j : idxs) proj.push_back(cs * (double)st.pts[j].x + sn * (double)st.pts[j].y);\n        sort(proj.begin(), proj.end());\n\n        double a1 = proj[kpos - 1];\n        double a2 = proj[kpos];\n        double gap = a2 - a1;\n        if (gap > bestGap) {\n            bestGap = gap;\n            bestTheta = theta;\n            bestU = 0.5 * (a1 + a2);\n        }\n    }\n\n    double lim = R * 0.98;\n    bestU = max(-lim, min(lim, bestU));\n    outLine = buildLine(bestTheta, bestU);\n    return true;\n}\n\n// Best-improvement postprocess: adaptively merge (deactivate) or split (activate) for histogram matching.\nstatic vector<Line> hillclimbPostprocess(const vector<Line>& inputLines,\n                                        const vector<Point>& pts,\n                                        const array<int,11>& a,\n                                        RNG& rng,\n                                        double timeBudgetSec) {\n    const int L = (int)inputLines.size();\n    State st;\n    st.N = (int)pts.size();\n    st.L = L;\n    st.pts = pts;\n    st.a = a;\n    st.lines = inputLines;\n    if (!st.buildInitialSignatures()) return inputLines;\n\n    int curD = st.distributed();\n    long long curS = st.secondaryScore();\n\n    vector<int> changed;\n    vector<Key> oldSig;\n\n    auto t0 = chrono::steady_clock::now();\n    int iter = 0;\n\n    while (true) {\n        double el = chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n        if (el > timeBudgetSec) break;\n        if (++iter > 20) break;\n\n        // compute deficits\n        int defSmall = 0, defLarge = 0;\n        array<int,11> def{};\n        for (int d = 1; d <= 10; d++) {\n            def[d] = max(0, st.a[d] - st.b[d]);\n            if (d <= 4) defSmall += def[d];\n            if (d >= 8) defLarge += def[d];\n        }\n\n        bool wantMerge = (defLarge > defSmall); // heuristic\n        bool improved = false;\n\n        // --- Try best merge by deactivation ---\n        if (wantMerge) {\n            int bestIdx = -1;\n            Line bestLine;\n            int bestD = curD;\n            long long bestS = curS;\n\n            // evaluate all active lines\n            for (int i = 0; i < L; i++) {\n                if (isInactive(st.lines[i])) continue;\n\n                Line cand = inactiveLineMatched(st, i, rng);\n\n                if (!st.applyReplaceLine(i, cand, changed, oldSig)) continue;\n                int nd = st.distributed();\n                long long ns = st.secondaryScore();\n\n                bool better = (nd > bestD) || (nd == bestD && ns > bestS);\n                st.rollbackReplaceLine(changed, oldSig);\n\n                if (better) {\n                    bestD = nd; bestS = ns;\n                    bestIdx = i; bestLine = cand;\n                }\n            }\n\n            if (bestIdx != -1 && (bestD > curD || (bestD == curD && bestS > curS))) {\n                // apply\n                st.applyReplaceLine(bestIdx, bestLine, changed, oldSig);\n                st.lines[bestIdx] = bestLine;\n                curD = bestD; curS = bestS;\n                improved = true;\n            }\n        }\n\n        // --- Try best split by activation (or modifying an inactive line) ---\n        if (!improved) {\n            // pick a target size with largest deficit (weighted towards medium/large a bit)\n            int targetD = 1;\n            long long bestNeed = -1;\n            for (int d = 1; d <= 10; d++) {\n                long long need = max(0, st.a[d] - st.b[d]);\n                if (need == 0) continue;\n                long long score = need * 100 + d * 8;\n                if (score > bestNeed) { bestNeed = score; targetD = d; }\n            }\n\n            // If no deficits, still try to reduce secondary penalties a bit by splitting large regions\n            bool haveDef = (bestNeed >= 0);\n\n            // find a focus region that can be split to produce targetD\n            int bestJ = -1;\n            int bestCnt = 0;\n            Key bestKey;\n            for (int t = 0; t < 90; t++) {\n                int j = rng.uniformInt(0, st.N - 1);\n                auto it = st.mp.find(st.sig[j]);\n                int c = (it == st.mp.end()) ? 0 : it->second;\n                if (haveDef) {\n                    if (c <= targetD) continue;\n                } else {\n                    if (c <= 10) continue;\n                }\n                if (c > bestCnt) {\n                    bestCnt = c;\n                    bestJ = j;\n                    bestKey = st.sig[j];\n                }\n            }\n\n            if (bestJ != -1) {\n                int useIdx = pickInactiveIndex(rng, st.lines);\n                int bestIdx = -1;\n                Line bestLine;\n                int bestD = curD;\n                long long bestS = curS;\n\n                // try several candidate split lines, keep best\n                for (int tr = 0; tr < 14; tr++) {\n                    Line cand;\n                    int desired = haveDef ? min(targetD, bestCnt - 1) : min(10, bestCnt - 1);\n                    desired = max(1, desired);\n                    if (!generateQuantileSplit(st, bestKey, bestCnt, desired, rng, cand)) continue;\n\n                    if (!st.applyReplaceLine(useIdx, cand, changed, oldSig)) continue;\n                    int nd = st.distributed();\n                    long long ns = st.secondaryScore();\n                    bool better = (nd > bestD) || (nd == bestD && ns > bestS);\n                    st.rollbackReplaceLine(changed, oldSig);\n\n                    if (better) {\n                        bestD = nd; bestS = ns;\n                        bestIdx = useIdx; bestLine = cand;\n                    }\n                }\n\n                if (bestIdx != -1 && (bestD > curD || (bestD == curD && bestS > curS))) {\n                    st.applyReplaceLine(bestIdx, bestLine, changed, oldSig);\n                    st.lines[bestIdx] = bestLine;\n                    curD = bestD; curS = bestS;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break; // local optimum for this postprocess\n    }\n\n    return st.lines;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n    array<int, 11> a{};\n    for (int d = 1; d <= 10; d++) cin >> a[d];\n    vector<Point> pts(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 2.93;\n    const int L = 100;\n    const int RESTARTS = 4;\n    const double PI = acos(-1.0);\n\n    int globalBestD = -1;\n    long long globalBestS = LLONG_MIN;\n    vector<Line> globalBestLines;\n\n    for (int rs = 0; rs < RESTARTS; rs++) {\n        double now = timer.elapsedSec();\n        if (now >= TIME_LIMIT) break;\n        double rem = TIME_LIMIT - now;\n        double budget = rem / (double)(RESTARTS - rs);\n\n        State st;\n        st.N = N; st.L = L; st.pts = pts; st.a = a;\n        st.lines.resize(L);\n\n        // init: moderate number of active lines; rest inactive.\n        int initActive = 52 + rs * 10; // diversified\n        initActive = max(35, min(92, initActive));\n\n        for (int i = 0; i < L; i++) {\n            double thetaBase = PI * (i + 0.5) / (double)L;\n            double theta = wrapTheta(thetaBase + rng.uniform(-0.03, 0.03));\n            if (i < initActive) st.lines[i] = randomActiveLineAnchored(rng, pts, theta, 1300.0);\n            else st.lines[i] = buildLine(theta, (rng.uniform01() < 0.5 ? +U_INACTIVE : -U_INACTIVE));\n        }\n\n        if (!st.buildInitialSignatures()) continue;\n\n        int curD = st.distributed();\n        long long curS = st.secondaryScore();\n        int bestD = curD;\n        long long bestS = curS;\n        vector<Line> bestLines = st.lines;\n\n        vector<int> changedIdx;\n        vector<Key> oldSig;\n\n        auto start = chrono::steady_clock::now();\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed >= budget) break;\n            double prog = elapsed / budget;\n\n            // two-temperature acceptance\n            double Td0 = 2.6, Td1 = 0.12;\n            double Ts0 = 260000.0, Ts1 = 9000.0;\n            double Td = Td0 * (1.0 - prog) + Td1 * prog;\n            double Ts = Ts0 * (1.0 - prog) + Ts1 * prog;\n\n            // compute deficit trend\n            int defSmall = 0, defLarge = 0;\n            for (int d = 1; d <= 4; d++) defSmall += max(0, st.a[d] - st.b[d]);\n            for (int d = 8; d <= 10; d++) defLarge += max(0, st.a[d] - st.b[d]);\n\n            // pick focus: region with large count\n            int focusJ = rng.uniformInt(0, N - 1);\n            int focusCnt = 0;\n            Key focusKey;\n\n            if (rng.uniform01() < 0.55) {\n                int bestJ = focusJ, bestCnt = 0;\n                for (int t = 0; t < 20; t++) {\n                    int j = rng.uniformInt(0, N - 1);\n                    auto it = st.mp.find(st.sig[j]);\n                    int c = (it == st.mp.end()) ? 0 : it->second;\n                    if (c > bestCnt) { bestCnt = c; bestJ = j; }\n                }\n                focusJ = bestJ;\n            }\n            focusKey = st.sig[focusJ];\n            {\n                auto it = st.mp.find(focusKey);\n                focusCnt = (it == st.mp.end()) ? 0 : it->second;\n            }\n\n            bool focusMove = (focusCnt > 10 && rng.uniform01() < 0.75);\n\n            // adaptive move weights\n            double pToggle = 0.10 + (defLarge > defSmall ? 0.05 : -0.02);\n            pToggle = max(0.05, min(0.18, pToggle));\n            double pQuant = 0.24 + (defSmall > defLarge ? 0.07 : -0.03);\n            pQuant = max(0.16, min(0.35, pQuant));\n            double pResample = 0.26;\n            double pPerturb = 1.0 - (pToggle + pQuant + pResample);\n            if (pPerturb < 0.15) { pPerturb = 0.15; pResample = 1.0 - (pToggle + pQuant + pPerturb); }\n\n            double r = rng.uniform01();\n\n            int idx = -1;\n            Line cand;\n\n            // (A) toggle activate/deactivate\n            if (r < pToggle) {\n                if (defLarge > defSmall) idx = pickActiveIndex(rng, st.lines);\n                else idx = pickInactiveIndex(rng, st.lines);\n\n                Line old = st.lines[idx];\n                if (isInactive(old)) {\n                    // activate near focus\n                    double theta = old.theta;\n                    double cs = cos(theta), sn = sin(theta);\n                    const Point& p = st.pts[focusJ];\n                    double projp = cs * (double)p.x + sn * (double)p.y;\n                    double u = projp + rng.uniform(-750.0, 750.0);\n                    double lim = R * 0.98;\n                    u = max(-lim, min(lim, u));\n                    cand = buildLine(theta, u);\n                } else {\n                    cand = inactiveLineMatched(st, idx, rng);\n                }\n            }\n            // (B) quantile split\n            else if (r < pToggle + pQuant && focusCnt >= 6) {\n                // prefer using inactive slot to add split\n                if (rng.uniform01() < 0.70) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                // choose target size with largest deficit feasible\n                int tMax = min(10, focusCnt - 1);\n                int targetD = 1;\n                long long bestNeed = -1;\n                for (int d = 1; d <= tMax; d++) {\n                    long long need = max(0, st.a[d] - st.b[d]);\n                    long long sc = need * 100 + d * 6;\n                    if (sc > bestNeed) { bestNeed = sc; targetD = d; }\n                }\n                if (bestNeed < 0) targetD = min(10, focusCnt - 1);\n\n                if (!generateQuantileSplit(st, focusKey, focusCnt, targetD, rng, cand)) {\n                    double theta = rng.uniform(0.0, PI);\n                    cand = randomActiveLineAnchored(rng, pts, theta, 1200.0);\n                }\n            }\n            // (C) resample active line near focus\n            else if (r < pToggle + pQuant + pResample || focusMove) {\n                if (defSmall >= defLarge && rng.uniform01() < 0.65) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                double theta = rng.uniform(0.0, PI);\n                double cs = cos(theta), sn = sin(theta);\n                const Point& p = st.pts[focusJ];\n                double projp = cs * (double)p.x + sn * (double)p.y;\n                double u = projp + rng.uniform(-850.0, 850.0);\n                double lim = R * 0.98;\n                u = max(-lim, min(lim, u));\n                cand = buildLine(theta, u);\n            }\n            // (D) perturb\n            else {\n                idx = rng.uniformInt(0, L - 1);\n                Line old = st.lines[idx];\n                cand = old;\n                double angleScale = 0.55 * (1.0 - prog) + 0.010;\n                double uScale = 5400.0 * (1.0 - prog) + 110.0;\n                cand.theta = wrapTheta(cand.theta + rng.uniform(-angleScale, angleScale));\n                cand.u += rng.uniform(-uScale, uScale);\n                cand.u = max(-U_INACTIVE, min(U_INACTIVE, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            }\n\n            int oldD = curD;\n            long long oldS = curS;\n\n            if (!st.applyReplaceLine(idx, cand, changedIdx, oldSig)) continue;\n\n            int newD = st.distributed();\n            long long newS = st.secondaryScore();\n\n            bool accept = false;\n            if (newD > oldD) accept = true;\n            else if (newD < oldD) {\n                double prob = exp((double)(newD - oldD) / Td);\n                if (rng.uniform01() < prob) accept = true;\n            } else {\n                long long dS = newS - oldS;\n                if (dS >= 0) accept = true;\n                else {\n                    double x = (double)dS / Ts;\n                    if (x > -60) {\n                        double prob = exp(x);\n                        if (rng.uniform01() < prob) accept = true;\n                    }\n                }\n            }\n\n            if (accept) {\n                st.lines[idx] = cand;\n                curD = newD;\n                curS = newS;\n                if (curD > bestD || (curD == bestD && curS > bestS)) {\n                    bestD = curD;\n                    bestS = curS;\n                    bestLines = st.lines;\n                }\n            } else {\n                st.rollbackReplaceLine(changedIdx, oldSig);\n            }\n        }\n\n        // Postprocess: best-improvement hillclimb (merge/split)\n        double remAll = TIME_LIMIT - timer.elapsedSec();\n        double postBudget = min(0.22, max(0.05, remAll * 0.30));\n        bestLines = hillclimbPostprocess(bestLines, pts, a, rng, postBudget);\n\n        // Evaluate postprocessed\n        {\n            State tmp;\n            tmp.N = N; tmp.L = L; tmp.pts = pts; tmp.a = a; tmp.lines = bestLines;\n            if (tmp.buildInitialSignatures()) {\n                bestD = tmp.distributed();\n                bestS = tmp.secondaryScore();\n            }\n        }\n\n        if (bestD > globalBestD || (bestD == globalBestD && bestS > globalBestS)) {\n            globalBestD = bestD;\n            globalBestS = bestS;\n            globalBestLines = bestLines;\n        }\n    }\n\n    if (globalBestLines.empty()) {\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n    cout << (int)globalBestLines.size() << \"\\n\";\n    for (auto& Lx : globalBestLines) {\n        cout << Lx.px << \" \" << Lx.py << \" \" << Lx.qx << \" \" << Lx.qy << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    explicit XorShift(uint64_t seed = 0) { x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstatic inline uint64_t maskRange64(int l, int r) {\n    if (l > r) return 0;\n    uint64_t left = (~0ULL) << l;\n    uint64_t right = (r == 63) ? ~0ULL : ((1ULL << (r + 1)) - 1ULL);\n    return left & right;\n}\n\nstruct Bits128 {\n    uint64_t lo = 0, hi = 0;\n    inline void set(int idx) { (idx < 64) ? (lo |= 1ULL << idx) : (hi |= 1ULL << (idx - 64)); }\n    inline void reset(int idx) { (idx < 64) ? (lo &= ~(1ULL << idx)) : (hi &= ~(1ULL << (idx - 64))); }\n    inline bool any() const { return lo || hi; }\n    inline Bits128 operator&(const Bits128& o) const { return Bits128{lo & o.lo, hi & o.hi}; }\n\n    inline bool anyInRange(int l, int r) const { // inclusive\n        if (l > r) return false;\n        uint64_t mlo = 0, mhi = 0;\n        if (l < 64) {\n            int rr = min(r, 63);\n            mlo = maskRange64(l, rr);\n        }\n        if (r >= 64) {\n            int ll = max(l, 64) - 64;\n            int rr = r - 64;\n            mhi = maskRange64(ll, rr);\n        }\n        return (lo & mlo) || (hi & mhi);\n    }\n};\n\nstruct Point { int x, y; };\n\nstruct Move {\n    Point p1, p2, p3, p4;\n    bool isAxis = true;\n    // axis params\n    int x1=0, y1=0, x2=0, y2=0;\n    // diag params (u=x+y, vIdx=x-y+shift)\n    int u1=0, u2=0, v1=0, v2=0;\n    int per = 0;\n    double val = -1e100;\n};\n\nstatic inline double linterp(double a, double b, double t) { return a + (b - a) * t; }\n\nstruct Params {\n    int topP = 240;\n    int midP = 1050;\n    int randP = 70;\n\n    double noise = 0.02;\n\n    // normal mode (progressive)\n    double alphaStart = 0.58, alphaEnd = 0.28;   // perimeter penalty\n    double betaStart  = 1.90, betaEnd  = 0.55;   // connectivity bonus\n    double deltaStart = 0.90, deltaEnd = 0.25;   // capacity bonus\n    double gammaStart = 32.0, gammaEnd = 8.0;    // tightness penalty (new)\n\n    // mild quadratic penalty\n    double alpha2Start = 0.0008, alpha2End = 0.0;\n\n    // epsilon-greedy (take 2nd best sometimes early)\n    double epsStart = 0.06, epsEnd = 0.00;\n\n    // fill fallback\n    double fillWcoef = 0.18;\n    double fillAlpha = 0.90;\n    double fillAlpha2 = 0.0014;\n    double fillBeta  = 1.05;\n    double fillDelta = 1.20;\n    double fillGamma = 40.0;\n    double fillEps   = 0.02;\n};\n\nstruct State {\n    int N;\n    int shiftV;\n    int U, V;\n\n    array<uint64_t, 61> dotRow{}; // y -> bits x\n    array<uint64_t, 61> dotCol{}; // x -> bits y\n\n    vector<Bits128> diagVdots; // vIdx -> bits u\n    vector<Bits128> antiUdots; // u -> bits vIdx\n\n    array<uint64_t, 61> hUsed{}; // y -> bits x seg (N-1 bits)\n    array<uint64_t, 61> vUsed{}; // x -> bits y seg (N-1 bits)\n    vector<uint64_t> d1SegUsed;  // vIdx -> bits pos along diag (len-1 bits)\n    vector<uint64_t> d2SegUsed;  // u -> bits pos along anti-diag (len-1 bits)\n\n    // used segment counts for O(1) free computation\n    array<uint8_t, 61> hCnt{};\n    array<uint8_t, 61> vCnt{};\n    vector<uint8_t> d1Cnt;\n    vector<uint8_t> d2Cnt;\n\n    // dot counts on lines (connectivity)\n    array<uint8_t, 61> rowCnt{};\n    array<uint8_t, 61> colCnt{};\n    vector<uint8_t> diagVCnt;\n    vector<uint8_t> antiUCnt;\n\n    int dots = 0;\n    long long sumW = 0;\n\n    State(int N_=0): N(N_) {}\n\n    inline bool hasDot(int x, int y) const { return (dotRow[y] >> x) & 1ULL; }\n\n    inline void addDot(int x, int y) {\n        dotRow[y] |= 1ULL << x;\n        dotCol[x] |= 1ULL << y;\n        rowCnt[y]++; colCnt[x]++;\n        int u = x + y;\n        int vIdx = x - y + shiftV;\n        diagVdots[vIdx].set(u);\n        antiUdots[u].set(vIdx);\n        diagVCnt[vIdx]++; antiUCnt[u]++;\n        dots++;\n    }\n\n    inline bool rowHasDotBetween(int y, int x1, int x2) const {\n        int l = min(x1, x2) + 1;\n        int r = max(x1, x2) - 1;\n        if (l > r) return false;\n        return (dotRow[y] & maskRange64(l, r)) != 0;\n    }\n    inline bool colHasDotBetween(int x, int y1, int y2) const {\n        int l = min(y1, y2) + 1;\n        int r = max(y1, y2) - 1;\n        if (l > r) return false;\n        return (dotCol[x] & maskRange64(l, r)) != 0;\n    }\n\n    inline uint64_t segMaskX(int x1, int x2) const {\n        int l = min(x1, x2);\n        int r = max(x1, x2) - 1;\n        return maskRange64(l, r);\n    }\n    inline uint64_t segMaskY(int y1, int y2) const {\n        int l = min(y1, y2);\n        int r = max(y1, y2) - 1;\n        return maskRange64(l, r);\n    }\n\n    inline void markH(int y, uint64_t m) {\n        uint64_t add = m & ~hUsed[y];\n        hUsed[y] |= m;\n        hCnt[y] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markV(int x, uint64_t m) {\n        uint64_t add = m & ~vUsed[x];\n        vUsed[x] |= m;\n        vCnt[x] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markD1(int vIdx, uint64_t m) {\n        uint64_t add = m & ~d1SegUsed[vIdx];\n        d1SegUsed[vIdx] |= m;\n        d1Cnt[vIdx] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markD2(int u, uint64_t m) {\n        uint64_t add = m & ~d2SegUsed[u];\n        d2SegUsed[u] |= m;\n        d2Cnt[u] += (uint8_t)__builtin_popcountll(add);\n    }\n\n    inline int lenD1(int vIdx) const {\n        int d = vIdx - shiftV;\n        return N - abs(d);\n    }\n    inline int lenD2(int u) const {\n        return N - abs(u - (N - 1));\n    }\n    inline int posD1(int vIdx, int x, int y) const {\n        int d = vIdx - shiftV;\n        return (d >= 0) ? y : x;\n    }\n    inline int posD2(int u, int x, int /*y*/) const {\n        int startX = (u < N) ? 0 : (u - (N - 1));\n        return x - startX;\n    }\n\n    inline uint64_t dMaskRange(int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        return (l <= r) ? maskRange64(l, r) : 0ULL;\n    }\n\n    inline bool d1FreeMask(int vIdx, uint64_t m) const { return (d1SegUsed[vIdx] & m) == 0; }\n    inline bool d2FreeMask(int u, uint64_t m) const { return (d2SegUsed[u] & m) == 0; }\n\n    inline Point uvToXY(int u, int vIdx) const {\n        int v = vIdx - shiftV;\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    inline int freeRowSeg(int y) const { return (N - 1) - (int)hCnt[y]; }\n    inline int freeColSeg(int x) const { return (N - 1) - (int)vCnt[x]; }\n    inline int freeD1Seg(int vIdx) const {\n        int seg = max(0, lenD1(vIdx) - 1);\n        return seg - (int)d1Cnt[vIdx];\n    }\n    inline int freeD2Seg(int u) const {\n        int seg = max(0, lenD2(u) - 1);\n        return seg - (int)d2Cnt[u];\n    }\n\n    inline bool canAxisRect(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 || y1 == y2) return false;\n        if (hasDot(x1, y1)) return false;\n        if (!hasDot(x2, y1) || !hasDot(x2, y2) || !hasDot(x1, y2)) return false;\n\n        if (rowHasDotBetween(y1, x1, x2)) return false;\n        if (rowHasDotBetween(y2, x1, x2)) return false;\n        if (colHasDotBetween(x1, y1, y2)) return false;\n        if (colHasDotBetween(x2, y1, y2)) return false;\n\n        uint64_t hm = segMaskX(x1, x2);\n        if ((hUsed[y1] & hm) || (hUsed[y2] & hm)) return false;\n        uint64_t vm = segMaskY(y1, y2);\n        if ((vUsed[x1] & vm) || (vUsed[x2] & vm)) return false;\n\n        return true;\n    }\n\n    inline void applyAxisRect(const Move& mv) {\n        uint64_t hm = segMaskX(mv.x1, mv.x2);\n        uint64_t vm = segMaskY(mv.y1, mv.y2);\n        markH(mv.y1, hm);\n        markH(mv.y2, hm);\n        markV(mv.x1, vm);\n        markV(mv.x2, vm);\n        addDot(mv.x1, mv.y1);\n    }\n\n    inline bool canDiagRect(int x1, int y1, int u2, int v2Idx) const {\n        if (hasDot(x1, y1)) return false;\n        int u1 = x1 + y1;\n        int v1Idx = x1 - y1 + shiftV;\n\n        // cond2 in (u,v)\n        if (diagVdots[v1Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (diagVdots[v2Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (antiUdots[u1].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n        if (antiUdots[u2].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n\n        Point p2 = uvToXY(u2, v1Idx);\n        Point p3 = uvToXY(u2, v2Idx);\n        Point p4 = uvToXY(u1, v2Idx);\n\n        auto in = [&](Point p) { return 0 <= p.x && p.x < N && 0 <= p.y && p.y < N; };\n        if (!in(p2) || !in(p3) || !in(p4)) return false;\n        if (!hasDot(p2.x, p2.y) || !hasDot(p3.x, p3.y) || !hasDot(p4.x, p4.y)) return false;\n\n        int uA = u2, uB = u1;\n        int vA = v1Idx, vB = v2Idx;\n\n        uint64_t m1 = dMaskRange(posD1(vA, x1, y1), posD1(vA, p2.x, p2.y));\n        if (!d1FreeMask(vA, m1)) return false;\n        uint64_t m2 = dMaskRange(posD2(uA, p2.x, p2.y), posD2(uA, p3.x, p3.y));\n        if (!d2FreeMask(uA, m2)) return false;\n        uint64_t m3 = dMaskRange(posD1(vB, p3.x, p3.y), posD1(vB, p4.x, p4.y));\n        if (!d1FreeMask(vB, m3)) return false;\n        uint64_t m4 = dMaskRange(posD2(uB, p4.x, p4.y), posD2(uB, x1, y1));\n        if (!d2FreeMask(uB, m4)) return false;\n\n        return true;\n    }\n\n    inline void applyDiagRect(const Move& mv) {\n        Point p2 = uvToXY(mv.u2, mv.v1);\n        Point p3 = uvToXY(mv.u2, mv.v2);\n        Point p4 = uvToXY(mv.u1, mv.v2);\n\n        uint64_t m1 = dMaskRange(posD1(mv.v1, mv.x1, mv.y1), posD1(mv.v1, p2.x, p2.y));\n        uint64_t m2 = dMaskRange(posD2(mv.u2, p2.x, p2.y), posD2(mv.u2, p3.x, p3.y));\n        uint64_t m3 = dMaskRange(posD1(mv.v2, p3.x, p3.y), posD1(mv.v2, p4.x, p4.y));\n        uint64_t m4 = dMaskRange(posD2(mv.u1, p4.x, p4.y), posD2(mv.u1, mv.x1, mv.y1));\n\n        markD1(mv.v1, m1);\n        markD2(mv.u2, m2);\n        markD1(mv.v2, m3);\n        markD2(mv.u1, m4);\n\n        addDot(mv.x1, mv.y1);\n    }\n};\n\nstruct Result {\n    vector<array<int, 8>> ops;\n    long long sumW = -1;\n    int dots = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int c = (N - 1) / 2;\n\n    vector<vector<int>> w(N, vector<int>(N, 0)); // w[x][y]\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) {\n        int dx = x - c, dy = y - c;\n        w[x][y] = dx * dx + dy * dy + 1;\n    }\n\n    vector<Point> initial(M);\n    for (int i = 0; i < M; i++) cin >> initial[i].x >> initial[i].y;\n\n    vector<Point> allPoints;\n    allPoints.reserve(N * N);\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) allPoints.push_back({x, y});\n    sort(allPoints.begin(), allPoints.end(), [&](const Point& a, const Point& b) {\n        int wa = w[a.x][a.y], wb = w[b.x][b.y];\n        if (wa != wb) return wa > wb;\n        if (a.x != b.x) return a.x < b.x;\n        return a.y < b.y;\n    });\n\n    auto start = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n    };\n\n    auto perimeterAxis = [&](int x1, int y1, int x2, int y2) -> int {\n        return 2 * (abs(x2 - x1) + abs(y2 - y1));\n    };\n    auto perimeterDiag_fromParams = [&](int u1, int u2, int v1, int v2, int /*shiftV*/) -> int {\n        // segments consumed = 2*a + 2*b where a=|u2-u1|/2, b=|v2-v1|/2\n        int a = abs(u2 - u1) / 2;\n        int b = abs(v2 - v1) / 2;\n        return 2 * (a + b);\n    };\n\n    auto runOnce = [&](uint64_t seed, const Params& par) -> Result {\n        XorShift rng(seed);\n\n        State st(N);\n        st.shiftV = N - 1;\n        st.U = 2 * N - 1;\n        st.V = 2 * N - 1;\n        st.diagVdots.assign(st.V, Bits128{});\n        st.antiUdots.assign(st.U, Bits128{});\n        st.d1SegUsed.assign(st.V, 0ULL);\n        st.d2SegUsed.assign(st.U, 0ULL);\n        st.d1Cnt.assign(st.V, 0);\n        st.d2Cnt.assign(st.U, 0);\n        st.diagVCnt.assign(st.V, 0);\n        st.antiUCnt.assign(st.U, 0);\n\n        for (auto &x : st.dotRow) x = 0;\n        for (auto &x : st.dotCol) x = 0;\n        for (auto &x : st.hUsed) x = 0;\n        for (auto &x : st.vUsed) x = 0;\n        for (auto &x : st.hCnt) x = 0;\n        for (auto &x : st.vCnt) x = 0;\n        for (auto &x : st.rowCnt) x = 0;\n        for (auto &x : st.colCnt) x = 0;\n\n        st.dots = 0;\n        st.sumW = 0;\n\n        for (auto p : initial) {\n            st.addDot(p.x, p.y);\n            st.sumW += w[p.x][p.y];\n        }\n\n        vector<array<int, 8>> ops;\n        ops.reserve(N * N);\n\n        auto collectP1 = [&](int P) {\n            vector<Point> res;\n            res.reserve(P + par.randP);\n            for (const auto& p : allPoints) {\n                if ((int)res.size() >= P) break;\n                if (!st.hasDot(p.x, p.y)) res.push_back(p);\n            }\n            for (int i = 0; i < par.randP; i++) {\n                for (int t = 0; t < 40; t++) {\n                    int x = rng.nextInt(0, N - 1);\n                    int y = rng.nextInt(0, N - 1);\n                    if (!st.hasDot(x, y)) { res.push_back({x, y}); break; }\n                }\n            }\n            return res;\n        };\n\n        auto evalMove = [&](const Move& mv, bool fillMode) -> double {\n            int x1 = mv.x1, y1 = mv.y1;\n            int u1 = x1 + y1;\n            int v1 = x1 - y1 + st.shiftV;\n            int conn = (int)st.rowCnt[y1] + (int)st.colCnt[x1] + (int)st.diagVCnt[v1] + (int)st.antiUCnt[u1];\n\n            int cap = 0;\n            double tight = 0.0;\n            if (mv.isAxis) {\n                int freeR1 = st.freeRowSeg(mv.y1), freeR2 = st.freeRowSeg(mv.y2);\n                int freeC1 = st.freeColSeg(mv.x1), freeC2 = st.freeColSeg(mv.x2);\n                cap = freeR1 + freeR2 + freeC1 + freeC2;\n\n                int dx = abs(mv.x2 - mv.x1);\n                int dy = abs(mv.y2 - mv.y1);\n                tight = (double)dx / (freeR1 + 1.0) + (double)dx / (freeR2 + 1.0)\n                      + (double)dy / (freeC1 + 1.0) + (double)dy / (freeC2 + 1.0);\n            } else {\n                int freeV1 = st.freeD1Seg(mv.v1), freeV2 = st.freeD1Seg(mv.v2);\n                int freeU1 = st.freeD2Seg(mv.u1), freeU2 = st.freeD2Seg(mv.u2);\n                cap = freeV1 + freeV2 + freeU1 + freeU2;\n\n                int a = abs(mv.u2 - mv.u1) / 2;\n                int b = abs(mv.v2 - mv.v1) / 2;\n                tight = (double)a / (freeV1 + 1.0) + (double)a / (freeV2 + 1.0)\n                      + (double)b / (freeU1 + 1.0) + (double)b / (freeU2 + 1.0);\n            }\n\n            double progress = (double)ops.size() / (double)max(1, (N * N - M));\n            progress = min(1.0, max(0.0, progress));\n\n            double alpha, beta, delta, gamma, a2, wcoef;\n            if (!fillMode) {\n                alpha = linterp(par.alphaStart, par.alphaEnd, progress);\n                beta  = linterp(par.betaStart,  par.betaEnd,  progress);\n                delta = linterp(par.deltaStart, par.deltaEnd, progress);\n                gamma = linterp(par.gammaStart, par.gammaEnd, progress);\n                a2    = linterp(par.alpha2Start, par.alpha2End, progress);\n                wcoef = 1.0;\n            } else {\n                alpha = par.fillAlpha;\n                beta  = par.fillBeta;\n                delta = par.fillDelta;\n                gamma = par.fillGamma;\n                a2    = par.fillAlpha2;\n                wcoef = par.fillWcoef;\n            }\n\n            double val = 0;\n            val += wcoef * (double)w[x1][y1];\n            val += beta * (double)conn;\n            val += delta * (double)cap;\n            val -= alpha * (double)mv.per;\n            val -= a2 * (double)mv.per * (double)mv.per;\n            val -= gamma * tight;                 // NEW\n            val += par.noise * rng.nextDouble();\n            return val;\n        };\n\n        auto findBestMove = [&](Move& chosen, bool fillMode) -> bool {\n            Move best, second;\n            bool hasBest = false, hasSecond = false;\n\n            auto update = [&](Move&& mv) {\n                mv.val = evalMove(mv, fillMode);\n                if (!hasBest || mv.val > best.val) {\n                    if (hasBest) { second = best; hasSecond = true; }\n                    best = mv; hasBest = true;\n                } else if ((!hasSecond || mv.val > second.val) && mv.val < best.val - 1e-12) {\n                    second = mv; hasSecond = true;\n                }\n            };\n\n            auto tryList = [&](int P) {\n                auto p1s = collectP1(P);\n                for (const auto& p1 : p1s) {\n                    int x1 = p1.x, y1 = p1.y;\n                    if (st.hasDot(x1, y1)) continue;\n\n                    // axis candidates\n                    uint64_t yMask = st.dotCol[x1];\n                    while (yMask) {\n                        int y2 = __builtin_ctzll(yMask);\n                        yMask &= yMask - 1;\n                        if (y2 == y1) continue;\n\n                        uint64_t inter = st.dotRow[y1] & st.dotRow[y2];\n                        inter &= ~(1ULL << x1);\n                        while (inter) {\n                            int x2 = __builtin_ctzll(inter);\n                            inter &= inter - 1;\n\n                            if (!st.canAxisRect(x1, y1, x2, y2)) continue;\n\n                            Move mv;\n                            mv.isAxis = true;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = {x2, y1};\n                            mv.p3 = {x2, y2};\n                            mv.p4 = {x1, y2};\n                            mv.x1 = x1; mv.y1 = y1; mv.x2 = x2; mv.y2 = y2;\n                            mv.per = perimeterAxis(x1, y1, x2, y2);\n                            update(std::move(mv));\n                        }\n                    }\n\n                    // diagonal candidates\n                    int u1 = x1 + y1;\n                    int v1Idx = x1 - y1 + st.shiftV;\n\n                    Bits128 vMask = st.antiUdots[u1];\n                    uint64_t vlo = vMask.lo, vhi = vMask.hi;\n\n                    auto handleV2 = [&](int v2Idx) {\n                        if (v2Idx == v1Idx) return;\n                        Bits128 interU = st.diagVdots[v1Idx] & st.diagVdots[v2Idx];\n                        if (u1 < 128) interU.reset(u1);\n                        if (!interU.any()) return;\n\n                        uint64_t ulo = interU.lo, uhi = interU.hi;\n\n                        auto handleU2 = [&](int u2) {\n                            if (u2 == u1) return;\n                            if (!st.canDiagRect(x1, y1, u2, v2Idx)) return;\n\n                            Point p2 = st.uvToXY(u2, v1Idx);\n                            Point p3 = st.uvToXY(u2, v2Idx);\n                            Point p4 = st.uvToXY(u1, v2Idx);\n\n                            Move mv;\n                            mv.isAxis = false;\n                            mv.p1 = {x1, y1};\n                            mv.p2 = p2;\n                            mv.p3 = p3;\n                            mv.p4 = p4;\n                            mv.x1 = x1; mv.y1 = y1;\n                            mv.u1 = u1; mv.u2 = u2;\n                            mv.v1 = v1Idx; mv.v2 = v2Idx;\n                            mv.per = perimeterDiag_fromParams(mv.u1, mv.u2, mv.v1, mv.v2, st.shiftV);\n                            update(std::move(mv));\n                        };\n\n                        while (ulo) { int b = __builtin_ctzll(ulo); ulo &= ulo - 1; handleU2(b); }\n                        while (uhi) { int b = __builtin_ctzll(uhi); uhi &= uhi - 1; handleU2(64 + b); }\n                    };\n\n                    while (vlo) { int b = __builtin_ctzll(vlo); vlo &= vlo - 1; handleV2(b); }\n                    while (vhi) { int b = __builtin_ctzll(vhi); vhi &= vhi - 1; handleV2(64 + b); }\n                }\n            };\n\n            if (!fillMode) {\n                tryList(par.topP);\n                if (!hasBest) tryList(par.midP);\n                if (!hasBest) tryList(N * N);\n            } else {\n                tryList(par.midP);\n                if (!hasBest) tryList(N * N);\n            }\n            if (!hasBest) return false;\n\n            double progress = (double)ops.size() / (double)max(1, (N * N - M));\n            progress = min(1.0, max(0.0, progress));\n            double eps = fillMode ? par.fillEps : linterp(par.epsStart, par.epsEnd, progress);\n\n            if (hasSecond && rng.nextDouble() < eps) chosen = second;\n            else chosen = best;\n            return true;\n        };\n\n        while (elapsedSec() < 4.92) {\n            Move mv;\n            if (!findBestMove(mv, false)) {\n                if (!findBestMove(mv, true)) break;\n            }\n\n            if (mv.isAxis) st.applyAxisRect(mv);\n            else st.applyDiagRect(mv);\n\n            st.sumW += w[mv.x1][mv.y1];\n            ops.push_back({mv.p1.x, mv.p1.y,\n                           mv.p2.x, mv.p2.y,\n                           mv.p3.x, mv.p3.y,\n                           mv.p4.x, mv.p4.y});\n        }\n\n        Result res;\n        res.ops = std::move(ops);\n        res.sumW = st.sumW;\n        res.dots = st.dots;\n        return res;\n    };\n\n    // Parameter variants: keep close to current best, only adjust gamma a bit\n    vector<Params> plist;\n    {\n        Params p;\n        p.topP = 240; p.midP = 1050; p.randP = 70;\n        p.gammaStart = 32.0; p.gammaEnd = 8.0;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 280; p.midP = 1250; p.randP = 80;\n        p.alphaStart = 0.55; p.alphaEnd = 0.26;\n        p.betaStart  = 1.75; p.betaEnd  = 0.50;\n        p.deltaStart = 1.00; p.deltaEnd = 0.28;\n        p.gammaStart = 28.0; p.gammaEnd = 7.0;\n        p.alpha2Start = 0.0007;\n        p.epsStart = 0.05;\n        p.fillGamma = 36.0;\n        p.noise = 0.022;\n        plist.push_back(p);\n    }\n    {\n        Params p;\n        p.topP = 210; p.midP = 950; p.randP = 65;\n        p.alphaStart = 0.60; p.alphaEnd = 0.30;\n        p.betaStart  = 2.05; p.betaEnd  = 0.62;\n        p.deltaStart = 0.80; p.deltaEnd = 0.22;\n        p.gammaStart = 36.0; p.gammaEnd = 9.0;\n        p.alpha2Start = 0.0010;\n        p.epsStart = 0.07;\n        p.fillGamma = 44.0;\n        p.noise = 0.018;\n        plist.push_back(p);\n    }\n\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result bestRes;\n    bestRes.sumW = -1;\n\n    int trial = 0;\n    while (elapsedSec() < 4.93) {\n        const Params& par = plist[trial % (int)plist.size()];\n        uint64_t seed = baseSeed + 1000003ULL * (uint64_t)trial;\n        auto res = runOnce(seed, par);\n        if (res.sumW > bestRes.sumW || (res.sumW == bestRes.sumW && res.ops.size() > bestRes.ops.size())) {\n            bestRes = std::move(res);\n        }\n        trial++;\n    }\n\n    cout << bestRes.ops.size() << \"\\n\";\n    for (auto &a : bestRes.ops) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << a[i];\n        }\n        cout << \"\\n\";\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int M = 100;\n\n// ---------------- RNG ----------------\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n    inline double next_double01() { return (next_u64() >> 11) * (1.0 / (1ULL << 53)); }\n};\n\n// ---------------- Board ----------------\nstruct Board {\n    array<uint8_t, M> a{}; // 0 empty, 1..3 flavors\n\n    // dir: 0=F(up),1=B(down),2=L(left),3=R(right)\n    inline void tilt(int dir) {\n        if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0, base = r * N;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = (c < k ? tmp[c] : 0);\n            }\n        } else if (dir == 3) { // R\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0, base = r * N;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = 0;\n                for (int i = 0; i < k; i++) a[base + (N - 1 - i)] = tmp[i];\n            }\n        } else if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = (r < k ? tmp[r] : 0);\n            }\n        } else { // B\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = 0;\n                for (int i = 0; i < k; i++) a[(N - 1 - i) * N + c] = tmp[i];\n            }\n        }\n    }\n\n    inline void place_by_p(int p, uint8_t flavor) {\n        int cnt = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                if (++cnt == p) { a[i] = flavor; return; }\n            }\n        }\n    }\n\n    inline void place_random_empty(uint8_t flavor, XorShift64 &rng) {\n        // Reservoir sampling (uniform among empties)\n        int chosen = -1, seen = 0;\n        for (int i = 0; i < M; i++) if (a[i] == 0) {\n            ++seen;\n            if (rng.next_int(seen) == 0) chosen = i;\n        }\n        if (chosen != -1) a[chosen] = flavor;\n    }\n\n    inline int filled_count() const {\n        int f = 0;\n        for (int i = 0; i < M; i++) f += (a[i] != 0);\n        return f;\n    }\n};\n\n// ---------------- Precompute ----------------\nstatic array<uint8_t, M> RR{}, CC{};\nstatic array<int, M> rightN{}, downN{};\n// cornerCloseness[k][i] where k=0..3 for corners (0,0),(0,9),(9,0),(9,9)\nstatic array<array<uint8_t, M>, 4> cornerCloseness{};\n\nstatic inline void init_pre() {\n    static const int CR[4] = {0, 0, 9, 9};\n    static const int CCc[4] = {0, 9, 0, 9};\n    for (int i = 0; i < M; i++) {\n        int r = i / N, c = i % N;\n        RR[i] = (uint8_t)r;\n        CC[i] = (uint8_t)c;\n        rightN[i] = (c + 1 < N ? i + 1 : -1);\n        downN[i]  = (r + 1 < N ? i + N : -1);\n\n        for (int k = 0; k < 4; k++) {\n            int dist = abs(r - CR[k]) + abs(c - CCc[k]); // 0..18\n            cornerCloseness[k][i] = (uint8_t)(18 - dist);\n        }\n    }\n}\n\n// ---------------- DSU ----------------\nstatic inline int dsu_find(int x, int *p) {\n    while (p[x] != x) {\n        p[x] = p[p[x]];\n        x = p[x];\n    }\n    return x;\n}\nstatic inline void dsu_unite(int a, int b, int *p, int *sz) {\n    a = dsu_find(a, p);\n    b = dsu_find(b, p);\n    if (a == b) return;\n    if (sz[a] < sz[b]) swap(a, b);\n    p[b] = a;\n    sz[a] += sz[b];\n}\n\n// returns component square sum; also outputs adjacency counts\nstatic inline long long comp_sq_sum_dsu(const Board &b, int &same_adj, int &diff_adj, int &empty_adj) {\n    int parent[M];\n    int sz[M];\n    for (int i = 0; i < M; i++) {\n        parent[i] = i;\n        sz[i] = (b.a[i] ? 1 : 0);\n    }\n\n    same_adj = diff_adj = empty_adj = 0;\n\n    for (int i = 0; i < M; i++) {\n        int j = rightN[i];\n        if (j != -1) {\n            uint8_t ai = b.a[i], aj = b.a[j];\n            if (!ai && !aj) empty_adj++;\n            else if (ai && aj) {\n                if (ai == aj) { same_adj++; dsu_unite(i, j, parent, sz); }\n                else diff_adj++;\n            }\n        }\n        j = downN[i];\n        if (j != -1) {\n            uint8_t ai = b.a[i], aj = b.a[j];\n            if (!ai && !aj) empty_adj++;\n            else if (ai && aj) {\n                if (ai == aj) { same_adj++; dsu_unite(i, j, parent, sz); }\n                else diff_adj++;\n            }\n        }\n    }\n\n    long long sumsq = 0;\n    for (int i = 0; i < M; i++) {\n        if (parent[i] == i && sz[i] > 0) sumsq += 1LL * sz[i] * sz[i];\n    }\n    return sumsq;\n}\n\n// ---------------- Shape (variance/separation + empty corner max) ----------------\nstruct ShapeFeat {\n    long long variance = 0;     // penalty\n    long long separation = 0;   // bonus\n    int empty_corner = 0;       // bonus (now: max over 4 corners)\n};\n\nstatic inline ShapeFeat compute_shape(const Board &b) {\n    long long cnt[4] = {0,0,0,0};\n    long long sumr[4] = {0,0,0,0}, sumc[4] = {0,0,0,0};\n    long long sumr2[4] = {0,0,0,0}, sumc2[4] = {0,0,0,0};\n\n    long long emptySum[4] = {0,0,0,0};\n\n    for (int i = 0; i < M; i++) {\n        uint8_t v = b.a[i];\n        if (!v) {\n            for (int k = 0; k < 4; k++) emptySum[k] += cornerCloseness[k][i];\n            continue;\n        }\n        int r = RR[i], c = CC[i];\n        cnt[v]++;\n        sumr[v] += r; sumc[v] += c;\n        sumr2[v] += 1LL * r * r;\n        sumc2[v] += 1LL * c * c;\n    }\n\n    ShapeFeat ft;\n    ft.empty_corner = (int)max( max(emptySum[0], emptySum[1]), max(emptySum[2], emptySum[3]) );\n\n    for (int f = 1; f <= 3; f++) {\n        if (cnt[f] <= 1) continue;\n        long long vr = sumr2[f] * cnt[f] - sumr[f] * sumr[f];\n        long long vc = sumc2[f] * cnt[f] - sumc[f] * sumc[f];\n        ft.variance += vr + vc;\n    }\n\n    for (int i = 1; i <= 3; i++) for (int j = i + 1; j <= 3; j++) {\n        if (cnt[i] == 0 || cnt[j] == 0) continue;\n        ft.separation += llabs(sumr[i] * cnt[j] - sumr[j] * cnt[i]);\n        ft.separation += llabs(sumc[i] * cnt[j] - sumc[j] * cnt[i]);\n    }\n\n    return ft;\n}\n\n// ---------------- Evaluation ----------------\nstatic inline long long full_eval(const Board &b) {\n    int filled = b.filled_count();\n\n    int same_adj, diff_adj, empty_adj;\n    long long cs = comp_sq_sum_dsu(b, same_adj, diff_adj, empty_adj);\n    ShapeFeat sh = compute_shape(b);\n\n    // Similar to the previous strong tuning, but corner-agnostic now.\n    long long wComp = (filled < 30 ? 450 : (filled < 70 ? 1650 : 3700));\n    long long wSame = (filled < 30 ? 120 : (filled < 70 ? 90   : 70));\n    long long wDiff = (filled < 30 ? 200 : (filled < 70 ? 140  : 110));\n    long long wVar  = (filled < 30 ? 3   : (filled < 70 ? 2    : 1));\n    long long wSep  = (filled < 30 ? 6   : (filled < 70 ? 4    : 2));\n\n    // slightly reduced to avoid over-bias now that we take max over corners\n    long long wEC   = (filled < 30 ? 100 : (filled < 70 ? 60   : 18));\n    long long wEmpA = 5;\n\n    return cs * wComp\n         + 1LL * same_adj * wSame\n         - 1LL * diff_adj * wDiff\n         - 1LL * sh.variance * wVar\n         + 1LL * sh.separation * wSep\n         + 1LL * sh.empty_corner * wEC\n         + 1LL * empty_adj * wEmpA;\n}\n\n// Cheaper fast eval for rollouts: adjacency + empty-corner(max)\nstatic inline int fast_eval_light(const Board &b) {\n    int same_adj = 0, diff_adj = 0, empty_adj = 0;\n    long long emptySum[4] = {0,0,0,0};\n\n    for (int i = 0; i < M; i++) {\n        if (b.a[i] == 0) {\n            for (int k = 0; k < 4; k++) emptySum[k] += cornerCloseness[k][i];\n        }\n        int j = rightN[i];\n        if (j != -1) {\n            uint8_t a = b.a[i], c = b.a[j];\n            if (!a && !c) empty_adj++;\n            else if (a && c) (a == c ? same_adj++ : diff_adj++);\n        }\n        j = downN[i];\n        if (j != -1) {\n            uint8_t a = b.a[i], c = b.a[j];\n            if (!a && !c) empty_adj++;\n            else if (a && c) (a == c ? same_adj++ : diff_adj++);\n        }\n    }\n\n    int empty_corner = (int)max( max(emptySum[0], emptySum[1]), max(emptySum[2], emptySum[3]) );\n\n    long long v = 0;\n    v += 120LL * same_adj;\n    v -= 160LL * diff_adj;\n    v += 10LL  * empty_adj;\n    v += 80LL  * empty_corner;\n\n    v = max<long long>(v, (long long)INT_MIN);\n    v = min<long long>(v, (long long)INT_MAX);\n    return (int)v;\n}\n\nstatic inline int rollout_policy_4dir(const Board &b, XorShift64 &rng) {\n    if (rng.next_double01() < 0.06) return rng.next_int(4);\n\n    int best = INT_MIN;\n    int bestDirs[4];\n    int k = 0;\n    for (int d = 0; d < 4; d++) {\n        Board nb = b;\n        nb.tilt(d);\n        int v = fast_eval_light(nb);\n        if (v > best) {\n            best = v;\n            k = 0;\n            bestDirs[k++] = d;\n        } else if (v == best) {\n            bestDirs[k++] = d;\n        }\n    }\n    return bestDirs[rng.next_int(k)];\n}\n\nstatic inline long long simulate_rollout(Board b, int t_next, int depth,\n                                        const array<uint8_t, 100> &flv,\n                                        XorShift64 &rng) {\n    for (int step = 0; step < depth && t_next < 100; step++, t_next++) {\n        b.place_random_empty(flv[t_next], rng);\n        if (t_next == 99) break;\n        int d = rollout_policy_4dir(b, rng);\n        b.tilt(d);\n    }\n    return full_eval(b);\n}\n\nstatic inline char dir_char(int d) {\n    static const char mp[4] = {'F','B','L','R'};\n    return mp[d];\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_pre();\n\n    array<uint8_t, 100> flv{};\n    for (int i = 0; i < 100; i++) {\n        int x; cin >> x;\n        flv[i] = (uint8_t)x;\n    }\n\n    // deterministic seed from flavor sequence\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < 100; i++) seed = (seed ^ flv[i]) * 1099511628211ULL;\n    XorShift64 rng(seed);\n\n    Board cur;\n\n    auto t_start = chrono::steady_clock::now();\n    const double TL = 1.985;\n\n    for (int t = 0; t < 100; t++) {\n        int p; cin >> p;\n        cur.place_by_p(p, flv[t]);\n\n        if (t == 99) break;\n\n        Board candB[4];\n        long double sum[4];\n        int cnt[4];\n\n        for (int d = 0; d < 4; d++) {\n            candB[d] = cur;\n            candB[d].tilt(d);\n            long long v = full_eval(candB[d]);\n            sum[d] = (long double)v;\n            cnt[d] = 1;\n        }\n\n        int remainMoves = 99 - t;\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n        double left = TL - elapsed;\n        if (left < 0) left = 0;\n\n        double base = (remainMoves > 0 ? left / remainMoves : 0.0);\n        double earlyFactor = 1.25 - 0.75 * (double)t / 99.0; // 1.25 -> 0.50\n        double budget = base * earlyFactor * 0.90;\n        budget = min(budget, 0.095);\n        budget = max(budget, 0.0015);\n\n        int remain = 99 - t;\n        int depth = (remain >= 70 ? 8 : (remain >= 40 ? 6 : (remain >= 20 ? 4 : 3)));\n        depth = min(depth, 100 - (t + 1));\n\n        auto move_end = chrono::steady_clock::now() + chrono::duration<double>(budget);\n\n        // Common random numbers: one seed per iteration shared among all 4 candidates\n        while (chrono::steady_clock::now() < move_end) {\n            uint64_t s = rng.next_u64();\n            for (int d = 0; d < 4; d++) {\n                XorShift64 local(s);\n                long long v = simulate_rollout(candB[d], t + 1, depth, flv, local);\n                sum[d] += (long double)v;\n                cnt[d] += 1;\n            }\n        }\n\n        int bestDir = 0;\n        long double bestVal = -1e300L;\n        for (int d = 0; d < 4; d++) {\n            long double avg = sum[d] / (long double)cnt[d];\n            if (avg > bestVal) {\n                bestVal = avg;\n                bestDir = d;\n            }\n        }\n\n        cout << dir_char(bestDir) << '\\n' << flush;\n        cur.tilt(bestDir);\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\n#include <csignal>\n#include <Eigen/Dense>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u64() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstatic long long C2ll(long long x){ return x*(x-1)/2; }\nstatic long long C3ll(long long x){ return x*(x-1)*(x-2)/6; }\n\nstatic vector<double> binom_pmf(int n, double p) {\n    vector<double> pmf(n+1, 0.0);\n    if (n==0) { pmf[0]=1.0; return pmf; }\n    if (p<=0.0) { pmf[0]=1.0; return pmf; }\n    if (p>=1.0) { pmf[n]=1.0; return pmf; }\n    double q = 1.0 - p;\n    pmf[0] = pow(q, n);\n    double ratio = p / q;\n    for (int k=1;k<=n;k++){\n        pmf[k] = pmf[k-1] * (double)(n-k+1) / (double)k * ratio;\n    }\n    return pmf;\n}\n\nstatic int choose_ms(double eps){\n    if (eps <= 0.15) return 1;\n    if (eps <= 0.25) return 2;\n    if (eps <= 0.33) return 3;\n    return 4;\n}\n\nstatic int chooseN_init(int M, double eps){\n    if (eps <= 0.00) return 13;\n    if (eps <= 0.01) return (M <= 95 ? 13 : 14);\n    if (eps <= 0.02) return 14;\n    if (eps <= 0.05) return 18;\n    if (eps <= 0.10) return 26;\n    if (eps <= 0.15) return 34;\n    if (eps <= 0.20) return 45;\n    if (eps <= 0.25) return 60;\n    if (eps <= 0.30) return 80;\n    if (eps <= 0.32) return 92;\n    return 100;\n}\n\nstruct Part {\n    vector<int> sz;     // clique sizes descending\n    int E = 0;          // sum C2(sz)\n    long long T_in = 0; // sum C3(sz)\n    long long S2 = 0;   // sum sz^2\n    long long S3 = 0;   // sum sz^3\n    int B = 0;\n    int mx = 0, mn = 0;\n};\n\nstatic Part make_part(const vector<int>& sz){\n    Part p;\n    p.sz = sz;\n    p.B = (int)sz.size();\n    p.mx = sz.empty() ? 0 : sz[0];\n    p.mn = sz.empty() ? 0 : sz.back();\n    long long E=0, T=0, S2=0, S3=0;\n    for(int x: sz){\n        E += C2ll(x);\n        T += C3ll(x);\n        S2 += 1LL*x*x;\n        S3 += 1LL*x*x*x;\n    }\n    p.E = (int)E;\n    p.T_in = T;\n    p.S2 = S2;\n    p.S3 = S3;\n    return p;\n}\n\nstatic string key_of(const vector<int>& v){\n    string s;\n    s.reserve(v.size() * 3);\n    for (int i=0;i<(int)v.size();i++){\n        if(i) s.push_back('-');\n        s += to_string(v[i]);\n    }\n    return s;\n}\n\nstatic double part_dist(const Part& a, const Part& b, int N, int L, long long totalTri){\n    auto norm = [](double x, double s){ return x / (s > 0 ? s : 1.0); };\n    double dE  = norm(abs(a.E - b.E), (double)L);\n    double dT  = norm((double)llabs(a.T_in - b.T_in), (double)max(1LL, totalTri));\n    double dS2 = norm((double)llabs(a.S2 - b.S2), (double)max(1LL, 1LL*N*N));\n    double dS3 = norm((double)llabs(a.S3 - b.S3), (double)max(1LL, 1LL*N*N*N));\n    double dB  = abs(a.B - b.B) / (double)max(1, N);\n    double dmx = abs(a.mx - b.mx) / (double)max(1, N);\n    double dmn = abs(a.mn - b.mn) / (double)max(1, N);\n    return 2.0*dE + 2.0*dT + 0.8*dS2 + 0.4*dS3 + 0.7*dB + 0.5*dmx + 0.3*dmn;\n}\n\n// Enumerate partitions of n with parts in [ms..maxPart], nonincreasing\nstatic void enum_partitions(int n, int maxPart, int ms, vector<int>& cur,\n                            unordered_set<string>& seen, vector<Part>& pool, int limit){\n    if ((int)pool.size() >= limit) return;\n    if (n == 0) {\n        string k = key_of(cur);\n        if (seen.insert(k).second) pool.push_back(make_part(cur));\n        return;\n    }\n    int up = min(maxPart, n);\n    for (int x = up; x >= ms; --x) {\n        cur.push_back(x);\n        enum_partitions(n - x, x, ms, cur, seen, pool, limit);\n        cur.pop_back();\n        if ((int)pool.size() >= limit) return;\n    }\n}\n\nstatic void add_deterministic_parts(int N, int ms, unordered_set<string>& seen, vector<Part>& pool, int limit){\n    auto add = [&](vector<int> v){\n        if ((int)pool.size() >= limit) return;\n        for (int x: v) if (x < ms) return;\n        sort(v.begin(), v.end(), greater<int>());\n        if (accumulate(v.begin(), v.end(), 0) != N) return;\n        string k = key_of(v);\n        if (seen.insert(k).second) pool.push_back(make_part(v));\n    };\n\n    add({N});\n    for(int a=ms; a<=min(N-ms, ms+24); a++) add({N-a, a});\n    for(int B=3; B<=12; B++){\n        if (B*ms > N) break;\n        int rem = N - B*ms;\n        int q = rem / B, r = rem % B;\n        vector<int> v(B, ms+q);\n        for(int i=0;i<r;i++) v[i]++;\n        add(v);\n    }\n}\n\nstatic void random_partitions(int N, int ms, double eps, SplitMix64& rng,\n                              unordered_set<string>& seen, vector<Part>& pool, int limit){\n    int Bmax;\n    if (eps <= 0.10) Bmax = 22;\n    else if (eps <= 0.20) Bmax = 15;\n    else if (eps <= 0.30) Bmax = 11;\n    else if (eps <= 0.35) Bmax = 9;\n    else Bmax = 8;\n    Bmax = min(Bmax, N / ms);\n    int Bmin = 1;\n    if (Bmax <= 0) return;\n\n    int tries = 0;\n    int maxTries = limit * 70;\n    while ((int)pool.size() < limit && tries < maxTries) {\n        tries++;\n        int B = rng.next_int(Bmin, Bmax);\n        if (B * ms > N) continue;\n        int rem = N - B * ms;\n\n        vector<int> cuts;\n        cuts.reserve(B+1);\n        cuts.push_back(0);\n        for (int i=0;i<B-1;i++) cuts.push_back(rng.next_int(0, rem));\n        cuts.push_back(rem);\n        sort(cuts.begin(), cuts.end());\n\n        vector<int> sz(B);\n        for (int i=0;i<B;i++) sz[i] = ms + (cuts[i+1] - cuts[i]);\n        sort(sz.begin(), sz.end(), greater<int>());\n\n        string k = key_of(sz);\n        if (!seen.insert(k).second) continue;\n        pool.push_back(make_part(sz));\n    }\n}\n\nstatic vector<Part> build_pool(int N, int ms, double eps, int poolTarget, SplitMix64& rng){\n    vector<Part> pool;\n    pool.reserve(poolTarget);\n    unordered_set<string> seen;\n    seen.reserve(poolTarget * 2);\n\n    add_deterministic_parts(N, ms, seen, pool, poolTarget);\n\n    if (N <= 32) {\n        vector<int> cur;\n        enum_partitions(N, N, ms, cur, seen, pool, poolTarget);\n    } else {\n        random_partitions(N, ms, eps, rng, seen, pool, poolTarget);\n    }\n    return pool;\n}\n\n// factorial falling nPk\nstatic long double fall(int n, int k){\n    if (k < 0) return 0;\n    if (k == 0) return 1;\n    if (k > n) return 0;\n    long double r = 1;\n    for(int i=0;i<k;i++) r *= (long double)(n - i);\n    return r;\n}\n\nstatic inline int popcnt_and(const vector<uint64_t>& a, const vector<uint64_t>& b){\n    int s = 0;\n    for (size_t i=0;i<a.size();i++) s += __builtin_popcountll(a[i] & b[i]);\n    return s;\n}\nstatic inline int get_edge_bit(const vector<uint64_t>& adjv, int u){\n    return (adjv[(size_t)u>>6] >> (u & 63)) & 1ULL;\n}\n\n// Compute internal edges for a fixed initial order assignment (no swapping).\nstatic int initial_internal_edges(\n    const vector<vector<uint64_t>>& adj,\n    const vector<int>& initOrder,\n    const vector<int>& partSizes\n){\n    int N = (int)adj.size();\n    int W = (int)adj[0].size();\n    int B = (int)partSizes.size();\n\n    vector<vector<uint64_t>> gbit(B, vector<uint64_t>(W, 0ULL));\n    vector<vector<int>> gverts(B);\n    gverts.assign(B, {});\n\n    int pos = 0;\n    for(int g=0; g<B; g++){\n        gverts[g].reserve(partSizes[g]);\n        for(int t=0; t<partSizes[g]; t++){\n            int v = initOrder[pos++];\n            gbit[g][(size_t)v>>6] |= 1ULL << (v & 63);\n            gverts[g].push_back(v);\n        }\n    }\n\n    long long sum = 0;\n    for(int g=0; g<B; g++){\n        for(int v: gverts[g]){\n            sum += popcnt_and(adj[v], gbit[g]);\n        }\n    }\n    return (int)(sum / 2);\n}\n\n// Local search starting from a given init order\nstatic int local_search_internal_edges(\n    const vector<vector<uint64_t>>& adj,\n    const vector<int>& initOrder,\n    const vector<int>& partSizes,\n    SplitMix64& rng,\n    int batches,\n    int samplesPerBatch\n){\n    int N = (int)adj.size();\n    int W = (int)adj[0].size();\n    int B = (int)partSizes.size();\n\n    vector<int> grp(N, -1);\n    vector<vector<uint64_t>> gbit(B, vector<uint64_t>(W, 0ULL));\n\n    int pos = 0;\n    for (int g=0; g<B; g++){\n        for (int t=0; t<partSizes[g]; t++){\n            int v = initOrder[pos++];\n            grp[v] = g;\n            gbit[g][(size_t)v>>6] |= 1ULL << (v & 63);\n        }\n    }\n\n    auto internal_edges = [&](){\n        long long sum = 0;\n        for (int v=0; v<N; v++){\n            sum += popcnt_and(adj[v], gbit[grp[v]]);\n        }\n        return (int)(sum / 2);\n    };\n\n    int curE = internal_edges();\n    int bestE = curE;\n\n    for (int b=0; b<batches; b++){\n        int bestDelta = 0, bestV = -1, bestU = -1;\n\n        for (int s=0; s<samplesPerBatch; s++){\n            int v = rng.next_int(0, N-1);\n            int u = rng.next_int(0, N-1);\n            if (u == v) continue;\n            int ga = grp[v], gb = grp[u];\n            if (ga == gb) continue;\n\n            int Av = popcnt_and(adj[v], gbit[ga]);\n            int Bv = popcnt_and(adj[v], gbit[gb]);\n            int Au = popcnt_and(adj[u], gbit[ga]);\n            int Bu = popcnt_and(adj[u], gbit[gb]);\n            int Auv = get_edge_bit(adj[v], u);\n\n            // delta for internal edges (counted once)\n            int delta = Au + Bv - Av - Bu - 2*Auv;\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestV = v; bestU = u;\n            }\n        }\n\n        if (bestDelta <= 0) break;\n\n        int v = bestV, u = bestU;\n        int ga = grp[v], gb = grp[u];\n\n        gbit[ga][(size_t)v>>6] ^= 1ULL << (v & 63);\n        gbit[gb][(size_t)v>>6] ^= 1ULL << (v & 63);\n        gbit[gb][(size_t)u>>6] ^= 1ULL << (u & 63);\n        gbit[ga][(size_t)u>>6] ^= 1ULL << (u & 63);\n\n        grp[v] = gb;\n        grp[u] = ga;\n\n        curE += bestDelta;\n        if (curE > bestE) bestE = curE;\n    }\n\n    return bestE;\n}\n\nint main(){\n    signal(SIGPIPE, SIG_IGN);\n\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    int ms = choose_ms(eps);\n\n    uint64_t seed0 = 0x123456789abcdefULL;\n    seed0 ^= (uint64_t)M * 1000003ULL;\n    seed0 ^= (uint64_t)llround(eps * 100000.0) * 10007ULL;\n    SplitMix64 rng(seed0);\n\n    int N = chooseN_init(M, eps);\n    const int poolTarget = 25000;\n\n    vector<Part> pool;\n    while (true) {\n        pool = build_pool(N, ms, eps, poolTarget, rng);\n        if ((int)pool.size() >= M) break;\n        if (N >= 100) break;\n        N++;\n    }\n\n    int L = N*(N-1)/2;\n    long long totalTri = C3ll(N);\n\n    // logP[s][d]\n    vector<vector<double>> logP(N+1, vector<double>(N, -1e100));\n    for (int s=1;s<=N;s++){\n        int n1=s-1, n2=N-s;\n        double p1=1.0-eps, p2=eps;\n        auto pmf1=binom_pmf(n1,p1);\n        auto pmf2=binom_pmf(n2,p2);\n        vector<double> conv(N,0.0);\n        for (int a=0;a<=n1;a++){\n            double pa=pmf1[a]; if(pa==0.0) continue;\n            for (int b=0;b<=n2;b++){\n                double pb=pmf2[b]; if(pb==0.0) continue;\n                conv[a+b] += pa*pb;\n            }\n        }\n        for (int d=0;d<=N-1;d++) logP[s][d] = log(max(conv[d], 1e-300));\n    }\n\n    int P = (int)pool.size();\n    if (P == 0) {\n        cout << 4 << \"\\n\";\n        for(int k=0;k<M;k++) cout << string(6,'0') << \"\\n\";\n        cout.flush();\n        for(int q=0;q<100;q++){\n            string H; cin >> H;\n            cout << 0 << \"\\n\";\n            cout.flush();\n        }\n        return 0;\n    }\n\n    // Farthest-point sampling to choose M partitions\n    vector<int> chosen;\n    chosen.reserve(M);\n    vector<char> used(P, 0);\n    vector<double> mind(P, 1e100);\n\n    int first = 0;\n    for (int i=1;i<P;i++) if (pool[i].S3 > pool[first].S3) first = i;\n    chosen.push_back(first);\n    used[first] = 1;\n    for (int i=0;i<P;i++) mind[i] = part_dist(pool[i], pool[first], N, L, totalTri);\n\n    while ((int)chosen.size() < M) {\n        int best = -1;\n        double bestVal = -1;\n        for (int i=0;i<P;i++){\n            if (used[i]) continue;\n            if (mind[i] > bestVal) { bestVal = mind[i]; best = i; }\n        }\n        if (best < 0) break;\n        used[best] = 1;\n        chosen.push_back(best);\n        for (int i=0;i<P;i++){\n            if (used[i]) continue;\n            double d = part_dist(pool[i], pool[best], N, L, totalTri);\n            if (d < mind[i]) mind[i] = d;\n        }\n    }\n    while ((int)chosen.size() < M) chosen.push_back(chosen.back());\n\n    // Precompute codebook stats\n    int Kspec = min(10, N);\n    bool useSpec = (eps >= 0.08 && N >= 30); // stabilize\n    double scale = (1.0 - 2.0*eps);\n\n    vector<vector<int>> codes(M);\n    vector<int> Pin(M,0);\n    vector<long long> type1(M,0), type2(M,0), type3(M,0);\n    vector<long double> wedgeMu(M, 0.0L), wedgeVar(M, 1.0L);\n    vector<array<double, 10>> expTop(M);\n\n    // comb for <=4\n    static long double Cc[5][5];\n    static bool inited=false;\n    if(!inited){\n        for(int i=0;i<=4;i++){\n            for(int j=0;j<=4;j++) Cc[i][j]=0;\n            Cc[i][0]=Cc[i][i]=1;\n            for(int j=1;j<i;j++) Cc[i][j]=Cc[i-1][j-1]+Cc[i-1][j];\n        }\n        inited=true;\n    }\n\n    for(int k=0;k<M;k++){\n        const Part& pp = pool[chosen[k]];\n        codes[k] = pp.sz;\n        Pin[k] = pp.E;\n\n        long long t1=0, t2=0;\n        for (int s: codes[k]) {\n            t1 += C3ll(s);\n            t2 += C2ll(s) * (long long)(N - s);\n        }\n        long long t3 = totalTri - t1 - t2;\n        type1[k]=t1; type2[k]=t2; type3[k]=t3;\n\n        // wedge moments approx\n        long double muW = 0.0L, varW = 0.0L;\n        long double p1 = (long double)(1.0 - eps);\n        long double p2 = (long double)(eps);\n\n        for(int s: codes[k]){\n            int n1 = s-1, n2 = N-s;\n            long double fx[5], fy[5];\n            for(int i=0;i<=4;i++){\n                fx[i] = fall(n1,i) * pow(p1, (long double)i);\n                fy[i] = fall(n2,i) * pow(p2, (long double)i);\n            }\n            auto F = [&](int kf)->long double{\n                long double res=0;\n                for(int i=0;i<=kf;i++) res += Cc[kf][i]*fx[i]*fy[kf-i];\n                return res;\n            };\n            long double F2 = F(2), F3 = F(3), F4 = F(4);\n            long double Ew = F2 / 2.0L;\n            long double E_f2_sq = F4 + 4.0L*F3 + 2.0L*F2;\n            long double Var_f2 = max((long double)0.0, E_f2_sq - F2*F2);\n            long double Varw = Var_f2 / 4.0L;\n\n            muW += (long double)s * Ew;\n            varW += (long double)s * Varw;\n        }\n        wedgeMu[k] = muW;\n        wedgeVar[k] = max(varW, 1e-3L);\n\n        for(int i=0;i<10;i++) expTop[k][i] = 0.0;\n        if (useSpec) {\n            vector<double> tops;\n            tops.reserve(codes[k].size());\n            for(int s: codes[k]) tops.push_back(scale * (double)(s-1));\n            sort(tops.begin(), tops.end(), greater<double>());\n            for(int i=0;i<min(Kspec,(int)tops.size());i++) expTop[k][i] = tops[i];\n        }\n    }\n\n    // Output codebook graphs (disjoint union of cliques)\n    cout << N << \"\\n\";\n    for (int k=0;k<M;k++){\n        const auto& part = codes[k];\n        vector<int> blk(N, -1);\n        int cur = 0;\n        for (int b=0;b<(int)part.size();b++){\n            for (int t=0;t<part[b];t++) blk[cur++] = b;\n        }\n        while (cur < N) blk[cur++] = (int)part.size();\n\n        string g;\n        g.reserve(L);\n        for (int i=0;i<N;i++){\n            for (int j=i+1;j<N;j++){\n                g.push_back(blk[i]==blk[j] ? '1' : '0');\n            }\n        }\n        if ((int)g.size() != L) g.assign(L, '0');\n        cout << g << \"\\n\";\n    }\n    cout.flush();\n\n    // Weights\n    double varE = max(1e-6, (double)L * eps * (1.0 - eps));\n    double wEdgeGlob  = (eps <= 0.05 ? 0.05 : (eps <= 0.20 ? 0.12 : 0.16));\n    double wTri       = (eps <= 0.10 ? 0.12 : (eps <= 0.25 ? 0.22 : 0.28));\n    double wWedge     = (eps <= 0.10 ? 0.08 : (eps <= 0.25 ? 0.14 : 0.18));\n\n    double wSpec  = 0.0, specScaleVar = 1.0;\n    if (useSpec) {\n        if (eps <= 0.15) wSpec = 0.18;\n        else if (eps <= 0.25) wSpec = 0.24;\n        else wSpec = 0.22;\n        wSpec *= (0.6 + 0.4 * min(1.0, N / 60.0));\n        specScaleVar = max(1e-6, (double)N * max(0.02, eps*(1.0-eps)));\n    }\n\n    // Local search controls\n    bool useLocal = (eps >= 0.10 && eps > 0.0);\n    int topK = min(M, (eps >= 0.30 ? 30 : (eps >= 0.20 ? 22 : 14)));\n    int batches = (eps >= 0.30 ? 55 : 45);\n    int samplesPerBatch = 500;\n    int extraRestartsTop = (eps >= 0.28 ? 8 : 0); // do one extra random restart for top few\n\n    // New: screening with initial internal edges\n    bool useInitEdgeScreen = (eps >= 0.12 && eps > 0.0);\n    double alphaInitEdge = (eps >= 0.28 ? 0.22 : (eps >= 0.18 ? 0.16 : 0.12)); // weight for screening only\n    double wPart = (eps > 0.0 ? log((1.0 - eps) / eps) : 0.0);\n\n    int W = (N + 63) / 64;\n\n    for(int q=0;q<100;q++){\n        string H;\n        if(!(cin >> H)) break;\n\n        vector<int> degRaw(N, 0);\n        int m = 0;\n        long long wedgeObs = 0;\n\n        vector<vector<uint64_t>> adj(N, vector<uint64_t>(W, 0ULL));\n        int idx=0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                char c = H[idx++];\n                if(c=='1'){\n                    degRaw[i]++; degRaw[j]++; m++;\n                    adj[i][(size_t)j>>6] |= 1ULL<<(j&63);\n                    adj[j][(size_t)i>>6] |= 1ULL<<(i&63);\n                }\n            }\n        }\n        for(int i=0;i<N;i++) wedgeObs += 1LL*degRaw[i]*(degRaw[i]-1)/2;\n\n        // triangles\n        long long tri3 = 0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                if ((adj[i][(size_t)j>>6] >> (j&63)) & 1ULL) {\n                    for(int w=0;w<W;w++) tri3 += __builtin_popcountll(adj[i][w] & adj[j][w]);\n                }\n            }\n        }\n        long long Tobs = tri3 / 3;\n\n        // degree order (for assignments)\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        stable_sort(order.begin(), order.end(), [&](int a, int b){\n            return degRaw[a] > degRaw[b];\n        });\n\n        // sorted degrees for degree-LL\n        vector<int> degSorted = degRaw;\n        sort(degSorted.begin(), degSorted.end(), greater<int>());\n\n        // spectrum (optional)\n        array<double, 10> obsTop{};\n        for(int i=0;i<10;i++) obsTop[i]=0.0;\n        if (useSpec) {\n            Eigen::MatrixXd C = Eigen::MatrixXd::Zero(N, N);\n            int id2=0;\n            for(int i=0;i<N;i++){\n                for(int j=i+1;j<N;j++){\n                    char c = H[id2++];\n                    double v = (c=='1') ? (1.0 - eps) : (-eps);\n                    C(i,j) = v; C(j,i) = v;\n                }\n            }\n            Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(C, Eigen::EigenvaluesOnly);\n            Eigen::VectorXd eigv = es.eigenvalues(); // ascending\n            for(int i=0;i<Kspec;i++) obsTop[i] = eigv[N-1-i];\n        }\n\n        // Score all candidates (cheap + optional init-edge screen)\n        vector<double> score(M, 0.0);\n        vector<int> initEin(M, 0);\n\n        for(int k=0;k<M;k++){\n            const auto& part = codes[k];\n\n            double sc = 0.0;\n            int pos = 0;\n            for(int s: part){\n                for(int t=0;t<s;t++){\n                    sc += logP[s][degSorted[pos++]];\n                }\n            }\n\n            // global edge-count penalty\n            if (eps > 0.0 && eps < 1.0){\n                double muE = eps*(double)L + (1.0 - 2.0*eps)*(double)Pin[k];\n                double z = (double)m - muE;\n                sc += wEdgeGlob * (-0.5 * (z*z) / varE);\n            }\n\n            // triangle penalty\n            {\n                double e = eps;\n                double p1 = (1.0-e)*(1.0-e)*(1.0-e);\n                double p2 = (1.0-e)*e*e;\n                double p3 = e*e*e;\n\n                double muT = (double)type1[k]*p1 + (double)type2[k]*p2 + (double)type3[k]*p3;\n                double varT =\n                    (double)type1[k]*p1*(1.0-p1) +\n                    (double)type2[k]*p2*(1.0-p2) +\n                    (double)type3[k]*p3*(1.0-p3);\n                varT = max(varT, 1e-6);\n\n                double z = (double)Tobs - muT;\n                sc += wTri * (-0.5 * (z*z) / varT);\n            }\n\n            // wedge penalty\n            {\n                long double muW = wedgeMu[k];\n                long double varW = wedgeVar[k];\n                long double z = (long double)wedgeObs - muW;\n                sc += wWedge * (double)(-0.5L * (z*z) / max(varW, 1e-3L));\n            }\n\n            // spectrum top-K penalty\n            if (useSpec) {\n                double diff = 0.0;\n                for(int i=0;i<Kspec;i++){\n                    double d = obsTop[i] - expTop[k][i];\n                    diff += d*d;\n                }\n                sc += wSpec * (-0.5 * diff / specScaleVar);\n            }\n\n            // NEW: init internal-edge screen\n            if (useInitEdgeScreen) {\n                int Ein0 = initial_internal_edges(adj, order, part);\n                initEin[k] = Ein0;\n                double llPart0 = wPart * (2.0 * (double)Ein0 - (double)Pin[k]);\n                sc += alphaInitEdge * llPart0;\n            }\n\n            score[k] = sc;\n        }\n\n        // shortlist topK\n        vector<int> idxs(M);\n        iota(idxs.begin(), idxs.end(), 0);\n        int K = min(topK, M);\n        nth_element(idxs.begin(), idxs.begin()+K-1, idxs.end(), [&](int a, int b){\n            return score[a] > score[b];\n        });\n        idxs.resize(K);\n        sort(idxs.begin(), idxs.end(), [&](int a, int b){\n            return score[a] > score[b];\n        });\n\n        int answer = idxs[0];\n\n        if (!useLocal) {\n            answer = idxs[0];\n        } else {\n            // refined selection using local search maximize internal edges (approx ML)\n            double bestVal = -1e300;\n\n            // per-query rng\n            uint64_t qseed = seed0 ^ (uint64_t)q * 0x9e3779b97f4a7c15ULL;\n            qseed ^= (uint64_t)m * 1000003ULL;\n            qseed ^= (uint64_t)(Tobs + 1) * 10007ULL;\n\n            for (int rank=0; rank<K; rank++){\n                int k = idxs[rank];\n\n                // 1st run: degree-order init\n                SplitMix64 r1(qseed ^ (uint64_t)k * 0x94d049bb133111ebULL);\n                int bestEin = local_search_internal_edges(adj, order, codes[k], r1, batches, samplesPerBatch);\n\n                // Extra random restart for top few candidates in hard regimes\n                if (rank < extraRestartsTop) {\n                    vector<int> rndOrder = order;\n                    // shuffle lightly: swap 20 random pairs\n                    for(int t=0;t<20;t++){\n                        int i = r1.next_int(0, N-1);\n                        int j = r1.next_int(0, N-1);\n                        swap(rndOrder[i], rndOrder[j]);\n                    }\n                    SplitMix64 r2(qseed ^ ((uint64_t)k<<1) ^ 0xbf58476d1ce4e5b9ULL);\n                    int Ein2 = local_search_internal_edges(adj, rndOrder, codes[k], r2, batches/2, samplesPerBatch);\n                    bestEin = max(bestEin, Ein2);\n                }\n\n                double ll = wPart * (2.0 * (double)bestEin - (double)Pin[k]);\n                double val = ll + 0.02 * score[k]; // tie-break stability\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    answer = k;\n                }\n            }\n        }\n\n        cout << answer << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstatic inline long long comb2(long long c) { return c * (c - 1) / 2; }\nstatic inline long double pow4(long double x) { long double s = x * x; return s * s; }\n\nstatic inline uint64_t morton11(uint32_t x, uint32_t y) {\n    uint64_t key = 0;\n    for (int b = 0; b < 11; b++) {\n        key |= (uint64_t)((x >> b) & 1u) << (2 * b);\n        key |= (uint64_t)((y >> b) & 1u) << (2 * b + 1);\n    }\n    return key;\n}\n\nstruct Edge {\n    int u, v;\n    long long w;\n    uint64_t key;\n    int prefDay;\n    long double imp; // [0,1]\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, D, K;\n    cin >> N >> M >> D >> K;\n\n    vector<Edge> edges(M);\n    vector<long long> W(M);\n    vector<vector<pair<int,int>>> g(N); // (to, edgeId)\n\n    for (int i = 0; i < M; i++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i].u = u; edges[i].v = v; edges[i].w = w;\n        W[i] = w;\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n\n    vector<int> X(N), Y(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n\n    vector<int> deg(N);\n    for (int v = 0; v < N; v++) deg[v] = (int)g[v].size();\n\n    auto t_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n\n    // time allocation (keep what worked)\n    const double TIME_END = 5.85;\n    const double SA_END   = 5.25;\n    const double EVAL_END = 5.65;\n\n    // ---- DFS spanning tree + LCA (for partial 2-edge-cut detection) ----\n    vector<int> parent(N, -1), parentEdge(N, -1), depth(N, 0);\n    vector<int> tin(N, -1), tout(N, -1), order;\n    vector<char> vis(N, 0), isTreeEdge(M, 0);\n    int timer = 0;\n\n    function<void(int)> dfs = [&](int v) {\n        vis[v] = 1;\n        tin[v] = timer++;\n        order.push_back(v);\n        for (auto [to, eid] : g[v]) {\n            if (to == parent[v]) continue;\n            if (!vis[to]) {\n                parent[to] = v;\n                parentEdge[to] = eid;\n                depth[to] = depth[v] + 1;\n                isTreeEdge[eid] = 1;\n                dfs(to);\n            }\n        }\n        tout[v] = timer++;\n    };\n    dfs(0);\n\n    int LOG = 1;\n    while ((1 << LOG) <= N) LOG++;\n    vector<vector<int>> up(LOG, vector<int>(N, -1));\n    for (int i = 0; i < N; i++) up[0][i] = parent[i];\n    for (int k = 1; k < LOG; k++) {\n        for (int i = 0; i < N; i++) {\n            int p = up[k-1][i];\n            up[k][i] = (p == -1 ? -1 : up[k-1][p]);\n        }\n    }\n\n    auto is_ancestor = [&](int a, int b) -> bool {\n        return tin[a] <= tin[b] && tout[b] <= tout[a];\n    };\n    auto lca = [&](int a, int b) -> int {\n        if (is_ancestor(a, b)) return a;\n        if (is_ancestor(b, a)) return b;\n        int v = a;\n        for (int k = LOG - 1; k >= 0; k--) {\n            int p = up[k][v];\n            if (p != -1 && !is_ancestor(p, b)) v = p;\n        }\n        return parent[v];\n    };\n\n    // ---- Detect many 2-edge-cuts of size 2 (tree edge + unique crossing back edge) ----\n    vector<long long> cntDelta(N, 0), cntSub(N, 0);\n    vector<int> xorDelta(N, 0), xorSub(N, 0);\n\n    for (int eid = 0; eid < M; eid++) {\n        if (isTreeEdge[eid]) continue;\n        int u = edges[eid].u, v = edges[eid].v;\n        int L = lca(u, v);\n        cntDelta[u] += 1;\n        cntDelta[v] += 1;\n        cntDelta[L] -= 2;\n        xorDelta[u] ^= eid;\n        xorDelta[v] ^= eid;\n    }\n    for (int i = 0; i < N; i++) { cntSub[i] = cntDelta[i]; xorSub[i] = xorDelta[i]; }\n    for (int idx = (int)order.size() - 1; idx >= 1; idx--) {\n        int v = order[idx];\n        int p = parent[v];\n        cntSub[p] += cntSub[v];\n        xorSub[p] ^= xorSub[v];\n    }\n\n    vector<vector<int>> conflict(M);\n    vector<pair<int,int>> conflictPairs;\n    for (int v = 1; v < N; v++) {\n        if (cntSub[v] == 1) {\n            int eTree = parentEdge[v];\n            int eNonTree = xorSub[v];\n            if (eTree >= 0 && eNonTree >= 0 && eTree != eNonTree) {\n                conflict[eTree].push_back(eNonTree);\n                conflict[eNonTree].push_back(eTree);\n                int a = min(eTree, eNonTree), b = max(eTree, eNonTree);\n                conflictPairs.push_back({a, b});\n            }\n        }\n    }\n    for (int i = 0; i < M; i++) {\n        auto &c = conflict[i];\n        sort(c.begin(), c.end());\n        c.erase(unique(c.begin(), c.end()), c.end());\n    }\n    sort(conflictPairs.begin(), conflictPairs.end());\n    conflictPairs.erase(unique(conflictPairs.begin(), conflictPairs.end()), conflictPairs.end());\n\n    // ---- Choose sources by farthest point sampling ----\n    int S = min(60, N);\n    vector<int> sources;\n    sources.reserve(S);\n    vector<long long> bestDist2(N, (1LL<<62));\n    sources.push_back(0);\n    bestDist2[0] = 0;\n    for (int it = 1; it < S; it++) {\n        int last = sources.back();\n        for (int v = 0; v < N; v++) {\n            long long dx = X[v] - X[last];\n            long long dy = Y[v] - Y[last];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 < bestDist2[v]) bestDist2[v] = d2;\n        }\n        int farV = 0;\n        for (int v = 1; v < N; v++) if (bestDist2[v] > bestDist2[farV]) farV = v;\n        sources.push_back(farV);\n    }\n\n    // ---- Importance: sampled Brandes edge-betweenness (weighted) ----\n    long double meanW = 0;\n    for (auto &e : edges) meanW += (long double)e.w;\n    meanW /= max(1, M);\n\n    vector<long double> rawImp(M, 0.0L);\n    const long long INF = (1LL<<62);\n    vector<long long> dist(N);\n    vector<long double> sigma(N), delta(N);\n    vector<vector<pair<int,int>>> preds(N); // (predVertex, edgeId)\n    vector<int> Sorder; Sorder.reserve(N);\n\n    for (int s : sources) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(sigma.begin(), sigma.end(), 0.0L);\n        for (int i = 0; i < N; i++) preds[i].clear();\n        Sorder.clear();\n\n        dist[s] = 0;\n        sigma[s] = 1.0L;\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dist[v]) continue;\n            Sorder.push_back(v);\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    pq.push({nd, to});\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back({v, eid});\n                } else if (nd == dist[to]) {\n                    sigma[to] += sigma[v];\n                    preds[to].push_back({v, eid});\n                }\n            }\n        }\n\n        fill(delta.begin(), delta.end(), 0.0L);\n        for (int idx = (int)Sorder.size() - 1; idx >= 0; idx--) {\n            int wv = Sorder[idx];\n            long double sw = sigma[wv];\n            if (sw == 0) continue;\n            for (auto [pv, eid] : preds[wv]) {\n                long double c = (sigma[pv] / sw) * (1.0L + delta[wv]);\n                delta[pv] += c;\n                long double factor = 1.0L + (long double)W[eid] / meanW;\n                rawImp[eid] += c * factor;\n            }\n        }\n    }\n\n    long double maxRaw = 1e-18L;\n    for (int i = 0; i < M; i++) maxRaw = max(maxRaw, rawImp[i]);\n    for (int i = 0; i < M; i++) edges[i].imp = rawImp[i] / maxRaw;\n\n    // ---- NEW: Boost importance for top-T edges using endpoint replacement path ----\n    // Compute altDist(u,v) without that edge; risk = (alt-w)/w, capped.\n    // This targets \u201cbottleneck but not necessarily high-betweenness in samples\u201d edges.\n    {\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b){ return edges[a].imp > edges[b].imp; });\n\n        int T = min(400, M);\n        vector<long long> dist2(N);\n\n        auto altDistUV = [&](int s, int t, int bannedEid) -> long long {\n            fill(dist2.begin(), dist2.end(), INF);\n            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            dist2[s] = 0;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top(); pq.pop();\n                if (d != dist2[v]) continue;\n                if (v == t) return d;\n                for (auto [to, eid] : g[v]) {\n                    if (eid == bannedEid) continue;\n                    long long nd = d + W[eid];\n                    if (nd < dist2[to]) {\n                        dist2[to] = nd;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            return INF;\n        };\n\n        const long double RISK_CAP = 30.0L; // cap detour ratio\n        const long double ALPHA = 0.9L;     // how strongly to boost\n\n        vector<long double> boosted(M);\n        for (int i = 0; i < M; i++) boosted[i] = edges[i].imp;\n\n        for (int k = 0; k < T; k++) {\n            int eid = idx[k];\n            int u = edges[eid].u, v = edges[eid].v;\n            long long w = edges[eid].w;\n            long long alt = altDistUV(u, v, eid);\n            long double riskRatio;\n            if (alt >= INF/4) {\n                riskRatio = RISK_CAP;\n            } else {\n                long long det = max(0LL, alt - w);\n                riskRatio = (long double)det / (long double)(w + 1);\n                if (riskRatio > RISK_CAP) riskRatio = RISK_CAP;\n            }\n            long double riskN = riskRatio / RISK_CAP; // [0,1]\n            boosted[eid] = edges[eid].imp * (1.0L + ALPHA * riskN);\n        }\n\n        long double mx = 1e-18L;\n        for (int i = 0; i < M; i++) mx = max(mx, boosted[i]);\n        for (int i = 0; i < M; i++) edges[i].imp = boosted[i] / mx;\n    }\n\n    // ---- PrefDay by Morton-order blocks ----\n    vector<int> idxKey(M);\n    iota(idxKey.begin(), idxKey.end(), 0);\n    for (int i = 0; i < M; i++) {\n        uint32_t mx = (uint32_t)(X[edges[i].u] + X[edges[i].v]);\n        uint32_t my = (uint32_t)(Y[edges[i].u] + Y[edges[i].v]);\n        edges[i].key = morton11(mx, my);\n    }\n    sort(idxKey.begin(), idxKey.end(), [&](int a, int b){ return edges[a].key < edges[b].key; });\n\n    int base = M / D, rem = M % D;\n    vector<int> desiredSize(D, base);\n    for (int d = 0; d < rem; d++) desiredSize[d]++;\n\n    {\n        int curp = 0;\n        for (int d = 0; d < D; d++) {\n            for (int t = 0; t < desiredSize[d]; t++) {\n                int eid = idxKey[curp++];\n                edges[eid].prefDay = d;\n            }\n        }\n    }\n\n    // ---- Greedy initial assignment: minimize \u0394pow4(load) + size dev + pref distance ----\n    vector<int> dayOfEdge(M, -1);\n    vector<vector<int>> inDay(D);\n    vector<int> posInDay(M, -1);\n    vector<vector<int>> inc(D, vector<int>(N, 0)); // removed incident count\n    vector<long double> sumImp(D, 0.0L);\n\n    vector<int> idxImp(M);\n    iota(idxImp.begin(), idxImp.end(), 0);\n    sort(idxImp.begin(), idxImp.end(), [&](int a, int b){\n        return edges[a].imp > edges[b].imp;\n    });\n\n    auto canPlace = [&](int e, int d) -> bool {\n        if ((int)inDay[d].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == d) return false;\n        int u = edges[e].u, v = edges[e].v;\n        if (inc[d][u] + 1 > deg[u] - 1) return false; // anti-isolation\n        if (inc[d][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    auto assignTo = [&](int e, int d) {\n        dayOfEdge[e] = d;\n        posInDay[e] = (int)inDay[d].size();\n        inDay[d].push_back(e);\n        inc[d][edges[e].u]++; inc[d][edges[e].v]++;\n        sumImp[d] += edges[e].imp;\n    };\n\n    const long double G_A = 1.0L;\n    const long double G_SZ = 0.18L;\n    const long double G_PD = 0.02L;\n\n    for (int e : idxImp) {\n        int pd = edges[e].prefDay;\n        int bestD = -1;\n        long double bestScore = 1e100L;\n        long double imp = edges[e].imp;\n\n        for (int r = 0; r < D; r++) {\n            int cand[2] = {pd - r, pd + r};\n            for (int t = 0; t < 2; t++) {\n                int d = cand[t];\n                if (d < 0 || d >= D) continue;\n                if (!canPlace(e, d)) continue;\n\n                long double before = pow4(sumImp[d]);\n                long double after  = pow4(sumImp[d] + imp);\n                long double dImp = after - before;\n\n                long double sz0 = (long double)inDay[d].size() - (long double)desiredSize[d];\n                long double sz1 = (long double)(inDay[d].size() + 1) - (long double)desiredSize[d];\n                long double dSz = (sz1*sz1 - sz0*sz0);\n\n                long double dPd = (long double)abs(d - pd);\n\n                long double score = G_A * dImp + G_SZ * dSz + G_PD * dPd;\n                if (score < bestScore) bestScore = score, bestD = d;\n            }\n            if (bestD != -1 && r >= 2) break;\n        }\n\n        if (bestD == -1) {\n            for (int d = 0; d < D; d++) if (canPlace(e, d)) { bestD = d; break; }\n        }\n        if (bestD == -1) { // last resort\n            for (int d = 0; d < D; d++) if ((int)inDay[d].size() < K) { bestD = d; break; }\n        }\n        assignTo(e, bestD);\n    }\n\n    auto applyMoveOnlyLists = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        int p = posInDay[e];\n        int last = inDay[od].back();\n        inDay[od][p] = last;\n        posInDay[last] = p;\n        inDay[od].pop_back();\n        posInDay[e] = (int)inDay[nd].size();\n        inDay[nd].push_back(e);\n        dayOfEdge[e] = nd;\n    };\n\n    auto basicMove = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        if (od == nd) return;\n        int u = edges[e].u, v = edges[e].v;\n        inc[od][u]--; inc[od][v]--;\n        inc[nd][u]++; inc[nd][v]++;\n        sumImp[od] -= edges[e].imp;\n        sumImp[nd] += edges[e].imp;\n        applyMoveOnlyLists(e, nd);\n    };\n\n    auto canPlaceNoConflictDay = [&](int e, int d) -> bool {\n        for (int p : conflict[e]) if (dayOfEdge[p] == d) return false;\n        return true;\n    };\n    auto vertexOkTo = [&](int e, int nd) -> bool {\n        int u = edges[e].u, v = edges[e].v;\n        return (inc[nd][u] + 1 <= deg[u] - 1) && (inc[nd][v] + 1 <= deg[v] - 1);\n    };\n\n    // Fix remaining detected conflicts\n    for (auto [a, b] : conflictPairs) {\n        if (dayOfEdge[a] != dayOfEdge[b]) continue;\n        int bad = dayOfEdge[a];\n        bool fixed = false;\n        for (int nd = 0; nd < D && !fixed; nd++) {\n            if (nd == bad) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(b, nd)) continue;\n            if (!vertexOkTo(b, nd)) continue;\n            basicMove(b, nd);\n            fixed = true;\n        }\n        for (int nd = 0; nd < D && !fixed; nd++) {\n            if (nd == bad) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(a, nd)) continue;\n            if (!vertexOkTo(a, nd)) continue;\n            basicMove(a, nd);\n            fixed = true;\n        }\n    }\n\n    // Fix isolation violations (safety)\n    auto fixIsolationOnce = [&]() -> bool {\n        for (int d = 0; d < D; d++) {\n            for (int v = 0; v < N; v++) {\n                if (inc[d][v] == deg[v]) {\n                    int bestE = -1;\n                    long double bestI = 1e100L;\n                    for (auto [to, eid] : g[v]) {\n                        (void)to;\n                        if (dayOfEdge[eid] != d) continue;\n                        if (edges[eid].imp < bestI) bestI = edges[eid].imp, bestE = eid;\n                    }\n                    if (bestE == -1) continue;\n                    for (int nd = 0; nd < D; nd++) {\n                        if (nd == d) continue;\n                        if ((int)inDay[nd].size() >= K) continue;\n                        if (!canPlaceNoConflictDay(bestE, nd)) continue;\n                        if (!vertexOkTo(bestE, nd)) continue;\n                        basicMove(bestE, nd);\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    };\n    for (int rep = 0; rep < 2000; rep++) if (!fixIsolationOnce()) break;\n\n    // ---- SA stats ----\n    const long double A = 1.0L;\n    const long double PV = 4.0L;\n    const long double SZ = 0.25L;\n    const long double B = 0.005L;\n\n    long long totalPairs = 0;\n    long double sumImp4 = 0;\n    long double sizeCost = 0;\n    long long misCount = 0;\n\n    for (int d = 0; d < D; d++) {\n        sumImp4 += pow4(sumImp[d]);\n        long long pairs = 0;\n        for (int v = 0; v < N; v++) pairs += comb2(inc[d][v]);\n        totalPairs += pairs;\n        long double diff = (long double)inDay[d].size() - (long double)desiredSize[d];\n        sizeCost += diff * diff;\n    }\n    for (int e = 0; e < M; e++) if (dayOfEdge[e] != edges[e].prefDay) misCount++;\n\n    long double curCost = A * sumImp4 + PV * (long double)totalPairs + SZ * sizeCost + B * (long double)misCount;\n\n    auto changeInc = [&](int day, int v, int dc) {\n        totalPairs -= comb2(inc[day][v]);\n        inc[day][v] += dc;\n        totalPairs += comb2(inc[day][v]);\n    };\n\n    auto hardCheckMove = [&](int e, int nd) -> bool {\n        int od = dayOfEdge[e];\n        if (od == nd) return false;\n        if ((int)inDay[nd].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == nd) return false;\n        int u = edges[e].u, v = edges[e].v;\n        if (inc[nd][u] + 1 > deg[u] - 1) return false;\n        if (inc[nd][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    auto hardCheckSwap = [&](int e1, int e2) -> bool {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        if (d1 == d2) return false;\n\n        auto newDay = [&](int e)->int {\n            if (e == e1) return d2;\n            if (e == e2) return d1;\n            return dayOfEdge[e];\n        };\n        for (int p : conflict[e1]) if (newDay(p) == d2) return false;\n        for (int p : conflict[e2]) if (newDay(p) == d1) return false;\n\n        vector<int> vs = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs.begin(), vs.end());\n        vs.erase(unique(vs.begin(), vs.end()), vs.end());\n\n        for (int v : vs) {\n            int c1 = inc[d1][v];\n            int c2 = inc[d2][v];\n            if (edges[e1].u == v) { c1--; c2++; }\n            if (edges[e1].v == v) { c1--; c2++; }\n            if (edges[e2].u == v) { c2--; c1++; }\n            if (edges[e2].v == v) { c2--; c1++; }\n            if (c1 > deg[v] - 1) return false;\n            if (c2 > deg[v] - 1) return false;\n        }\n        return true;\n    };\n\n    auto applyMoveSA = [&](int e, int nd) {\n        int od = dayOfEdge[e];\n        long double imp = edges[e].imp;\n\n        long double a0 = sumImp[od], b0 = sumImp[nd];\n        long double a1 = a0 - imp, b1 = b0 + imp;\n        long double deltaImp4 = pow4(a1) + pow4(b1) - pow4(a0) - pow4(b0);\n\n        long double so0 = (long double)inDay[od].size();\n        long double sn0 = (long double)inDay[nd].size();\n        long double dso = so0 - (long double)desiredSize[od];\n        long double dsn = sn0 - (long double)desiredSize[nd];\n        long double dso1 = (so0 - 1.0L) - (long double)desiredSize[od];\n        long double dsn1 = (sn0 + 1.0L) - (long double)desiredSize[nd];\n        long double deltaSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n        long long oldMis = (od != edges[e].prefDay);\n        long long newMis = (nd != edges[e].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        long long pairsBefore = totalPairs;\n        int u = edges[e].u, v = edges[e].v;\n        changeInc(od, u, -1); changeInc(od, v, -1);\n        changeInc(nd, u, +1); changeInc(nd, v, +1);\n        long long deltaPairs = totalPairs - pairsBefore;\n\n        curCost += A * deltaImp4 + PV * (long double)deltaPairs + SZ * deltaSize + B * (long double)deltaMis;\n\n        sumImp4 += deltaImp4;\n        sizeCost += deltaSize;\n        misCount += deltaMis;\n        sumImp[od] = a1;\n        sumImp[nd] = b1;\n\n        applyMoveOnlyLists(e, nd);\n    };\n\n    auto applySwapSA = [&](int e1, int e2) {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n\n        long double s1 = sumImp[d1], s2 = sumImp[d2];\n        long double ns1 = s1 - i1 + i2;\n        long double ns2 = s2 - i2 + i1;\n        long double deltaImp4 = pow4(ns1) + pow4(ns2) - pow4(s1) - pow4(s2);\n\n        long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n        long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n        long long deltaMis = newMis - oldMis;\n\n        long long pairsBefore = totalPairs;\n        changeInc(d1, edges[e1].u, -1); changeInc(d1, edges[e1].v, -1);\n        changeInc(d2, edges[e1].u, +1); changeInc(d2, edges[e1].v, +1);\n        changeInc(d2, edges[e2].u, -1); changeInc(d2, edges[e2].v, -1);\n        changeInc(d1, edges[e2].u, +1); changeInc(d1, edges[e2].v, +1);\n        long long deltaPairs = totalPairs - pairsBefore;\n\n        curCost += A * deltaImp4 + PV * (long double)deltaPairs + B * (long double)deltaMis;\n\n        sumImp4 += deltaImp4;\n        misCount += deltaMis;\n        sumImp[d1] = ns1;\n        sumImp[d2] = ns2;\n\n        applyMoveOnlyLists(e1, d2);\n        applyMoveOnlyLists(e2, d1);\n    };\n\n    // ---- Simulated annealing ----\n    XorShift64 rng(123456789);\n    while (elapsedSec() < SA_END) {\n        double t = elapsedSec() / SA_END;\n        double T = 3.5 * (1.0 - t) + 0.05 * t;\n\n        int op = rng.nextInt(100);\n        if (op < 72) {\n            int e1 = rng.nextInt(M);\n            int e2 = rng.nextInt(M);\n            if (e1 == e2) continue;\n            if (dayOfEdge[e1] == dayOfEdge[e2]) continue;\n            if (!hardCheckSwap(e1, e2)) continue;\n\n            int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n            long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n\n            long double s1 = sumImp[d1], s2 = sumImp[d2];\n            long double ns1 = s1 - i1 + i2;\n            long double ns2 = s2 - i2 + i1;\n            long double deltaImp4 = pow4(ns1) + pow4(ns2) - pow4(s1) - pow4(s2);\n\n            long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n            long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            struct Mod { int day, v, dc; };\n            array<Mod,8> mods = {{\n                {d1, edges[e1].u, -1}, {d1, edges[e1].v, -1},\n                {d2, edges[e1].u, +1}, {d2, edges[e1].v, +1},\n                {d2, edges[e2].u, -1}, {d2, edges[e2].v, -1},\n                {d1, edges[e2].u, +1}, {d1, edges[e2].v, +1},\n            }};\n            long long deltaPairs = 0;\n            for (int i = 0; i < 8; i++) {\n                int day = mods[i].day, v = mods[i].v;\n                int dc = mods[i].dc;\n                if (dc == 0) continue;\n                for (int j = i+1; j < 8; j++) {\n                    if (mods[j].day == day && mods[j].v == v) {\n                        dc += mods[j].dc;\n                        mods[j].dc = 0;\n                    }\n                }\n                int oldc = inc[day][v];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            }\n\n            long double delta = A * deltaImp4 + PV * (long double)deltaPairs + B * (long double)deltaMis;\n            bool accept = (delta <= 0) || (rng.nextDouble() < exp(-(double)delta / T));\n            if (accept) applySwapSA(e1, e2);\n\n        } else {\n            int e = rng.nextInt(M);\n            int nd = rng.nextInt(D);\n            if (!hardCheckMove(e, nd)) continue;\n\n            int od = dayOfEdge[e];\n            long double imp = edges[e].imp;\n\n            long double a0 = sumImp[od], b0 = sumImp[nd];\n            long double a1 = a0 - imp, b1 = b0 + imp;\n            long double deltaImp4 = pow4(a1) + pow4(b1) - pow4(a0) - pow4(b0);\n\n            long double so0 = (long double)inDay[od].size();\n            long double sn0 = (long double)inDay[nd].size();\n            long double dso = so0 - (long double)desiredSize[od];\n            long double dsn = sn0 - (long double)desiredSize[nd];\n            long double dso1 = (so0 - 1.0L) - (long double)desiredSize[od];\n            long double dsn1 = (sn0 + 1.0L) - (long double)desiredSize[nd];\n            long double deltaSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n            long long oldMis = (od != edges[e].prefDay);\n            long long newMis = (nd != edges[e].prefDay);\n            long long deltaMis = newMis - oldMis;\n\n            int u = edges[e].u, v = edges[e].v;\n            long long deltaPairs = 0;\n            auto updOne = [&](int day, int vert, int dc) {\n                int oldc = inc[day][vert];\n                int newc = oldc + dc;\n                deltaPairs += (comb2(newc) - comb2(oldc));\n            };\n            updOne(od, u, -1); updOne(od, v, -1);\n            updOne(nd, u, +1); updOne(nd, v, +1);\n\n            long double delta = A * deltaImp4 + PV * (long double)deltaPairs + SZ * deltaSize + B * (long double)deltaMis;\n            bool accept = (delta <= 0) || (rng.nextDouble() < exp(-(double)delta / T));\n            if (accept) applyMoveSA(e, nd);\n        }\n    }\n\n    // ---- Eval-guided improvement (same as your best version) ----\n    int EvalS = min(10, (int)sources.size());\n    vector<int> evalSources(sources.begin(), sources.begin() + EvalS);\n\n    auto dijkstraDay = [&](int s, int skipDay, vector<long long> &dout) {\n        fill(dout.begin(), dout.end(), INF);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dout[s] = 0;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dout[v]) continue;\n            for (auto [to, eid] : g[v]) {\n                if (skipDay >= 0 && dayOfEdge[eid] == skipDay) continue;\n                long long nd = d + W[eid];\n                if (nd < dout[to]) {\n                    dout[to] = nd;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    };\n\n    vector<vector<long long>> distFull(EvalS, vector<long long>(N, INF));\n    for (int i = 0; i < EvalS; i++) dijkstraDay(evalSources[i], -1, distFull[i]);\n\n    vector<long long> tmpDist(N, INF);\n    auto dayDamage = [&](int day) -> long long {\n        long long score = 0;\n        for (int i = 0; i < EvalS; i++) {\n            dijkstraDay(evalSources[i], day, tmpDist);\n            for (int v = 0; v < N; v++) {\n                long long a = tmpDist[v];\n                if (a >= INF/4) a = 1000000000LL;\n                long long b = distFull[i][v];\n                long long incv = a - b;\n                if (incv > 0) score += incv;\n            }\n        }\n        return score;\n    };\n\n    vector<long long> dmg(D, 0);\n    for (int d = 0; d < D; d++) dmg[d] = dayDamage(d);\n\n    auto canMoveBasic = [&](int e, int nd) -> bool {\n        int od = dayOfEdge[e];\n        if (od == nd) return false;\n        if ((int)inDay[nd].size() >= K) return false;\n        for (int p : conflict[e]) if (dayOfEdge[p] == nd) return false;\n        int u = edges[e].u, v = edges[e].v;\n        if (inc[nd][u] + 1 > deg[u] - 1) return false;\n        if (inc[nd][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    auto canSwapBasic = [&](int e1, int e2) -> bool {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        if (d1 == d2) return false;\n\n        auto newDay = [&](int e)->int {\n            if (e == e1) return d2;\n            if (e == e2) return d1;\n            return dayOfEdge[e];\n        };\n        for (int p : conflict[e1]) if (newDay(p) == d2) return false;\n        for (int p : conflict[e2]) if (newDay(p) == d1) return false;\n\n        vector<int> vs = {edges[e1].u, edges[e1].v, edges[e2].u, edges[e2].v};\n        sort(vs.begin(), vs.end());\n        vs.erase(unique(vs.begin(), vs.end()), vs.end());\n\n        for (int v : vs) {\n            int c1 = inc[d1][v];\n            int c2 = inc[d2][v];\n            if (edges[e1].u == v) { c1--; c2++; }\n            if (edges[e1].v == v) { c1--; c2++; }\n            if (edges[e2].u == v) { c2--; c1++; }\n            if (edges[e2].v == v) { c2--; c1++; }\n            if (c1 > deg[v] - 1) return false;\n            if (c2 > deg[v] - 1) return false;\n        }\n        return true;\n    };\n\n    auto doSwapBasic = [&](int e1, int e2) {\n        int d1 = dayOfEdge[e1], d2 = dayOfEdge[e2];\n        int a1 = edges[e1].u, b1 = edges[e1].v;\n        int a2 = edges[e2].u, b2 = edges[e2].v;\n        inc[d1][a1]--; inc[d1][b1]--;\n        inc[d2][a1]++; inc[d2][b1]++;\n        inc[d2][a2]--; inc[d2][b2]--;\n        inc[d1][a2]++; inc[d1][b2]++;\n        sumImp[d1] = sumImp[d1] - edges[e1].imp + edges[e2].imp;\n        sumImp[d2] = sumImp[d2] - edges[e2].imp + edges[e1].imp;\n        applyMoveOnlyLists(e1, d2);\n        applyMoveOnlyLists(e2, d1);\n    };\n\n    while (elapsedSec() < EVAL_END) {\n        int hi = 0;\n        for (int d = 1; d < D; d++) if (dmg[d] > dmg[hi]) hi = d;\n\n        vector<int> lows(D);\n        iota(lows.begin(), lows.end(), 0);\n        sort(lows.begin(), lows.end(), [&](int a, int b){ return dmg[a] < dmg[b]; });\n\n        bool improved = false;\n        int loTry = min(3, D);\n\n        for (int tlo = 0; tlo < loTry && !improved; tlo++) {\n            int lo = lows[tlo];\n            if (lo == hi) continue;\n\n            // MOVE (if slack)\n            if ((int)inDay[lo].size() < K) {\n                int sz = (int)inDay[hi].size();\n                if (sz > 0) {\n                    int bestE = -1;\n                    long double bestImp = -1;\n                    int sampleCnt = min(40, sz);\n                    for (int t = 0; t < sampleCnt; t++) {\n                        int e = inDay[hi][rng.nextInt(sz)];\n                        if (!canMoveBasic(e, lo)) continue;\n                        if (edges[e].imp > bestImp) bestImp = edges[e].imp, bestE = e;\n                    }\n                    if (bestE != -1) {\n                        long long oldHi = dmg[hi], oldLo = dmg[lo];\n                        basicMove(bestE, lo);\n                        long long newHi = dayDamage(hi);\n                        long long newLo = dayDamage(lo);\n                        if (newHi + newLo < oldHi + oldLo) {\n                            dmg[hi] = newHi; dmg[lo] = newLo;\n                            improved = true;\n                            break;\n                        } else {\n                            basicMove(bestE, hi); // revert\n                        }\n                    }\n                }\n            }\n\n            // SWAP\n            {\n                int szH = (int)inDay[hi].size();\n                int szL = (int)inDay[lo].size();\n                if (szH == 0 || szL == 0) continue;\n\n                int bestE1 = -1, bestE2 = -1;\n                long double bestKey = -1;\n                int tries = 40;\n                for (int t = 0; t < tries; t++) {\n                    int e1 = inDay[hi][rng.nextInt(szH)];\n                    int e2 = inDay[lo][rng.nextInt(szL)];\n                    if (edges[e1].imp < edges[e2].imp) continue;\n                    if (!canSwapBasic(e1, e2)) continue;\n                    long double key = edges[e1].imp - edges[e2].imp;\n                    if (key > bestKey) bestKey = key, bestE1 = e1, bestE2 = e2;\n                }\n\n                if (bestE1 != -1) {\n                    long long oldHi = dmg[hi], oldLo = dmg[lo];\n                    doSwapBasic(bestE1, bestE2);\n                    long long newHi = dayDamage(hi);\n                    long long newLo = dayDamage(lo);\n                    if (newHi + newLo < oldHi + oldLo) {\n                        dmg[hi] = newHi; dmg[lo] = newLo;\n                        improved = true;\n                        break;\n                    } else {\n                        doSwapBasic(bestE1, bestE2); // revert swap\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    // ---- Connectivity repair (final safety) ----\n    vector<int> comp(N, -1);\n    auto compCountForDay = [&](int d) -> int {\n        fill(comp.begin(), comp.end(), -1);\n        int cid = 0;\n        deque<int> q;\n        for (int s = 0; s < N; s++) {\n            if (comp[s] != -1) continue;\n            comp[s] = cid++;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                for (auto [to, eid] : g[v]) {\n                    if (dayOfEdge[eid] == d) continue; // closed\n                    if (comp[to] != -1) continue;\n                    comp[to] = comp[v];\n                    q.push_back(to);\n                }\n            }\n        }\n        return cid;\n    };\n\n    auto tryMoveEdgeToSomeDay = [&](int e, int fromDay) -> bool {\n        int u = edges[e].u, v = edges[e].v;\n        vector<int> days(D);\n        iota(days.begin(), days.end(), 0);\n        sort(days.begin(), days.end(), [&](int a, int b){ return inDay[a].size() < inDay[b].size(); });\n        for (int nd : days) {\n            if (nd == fromDay) continue;\n            if ((int)inDay[nd].size() >= K) continue;\n            if (!canPlaceNoConflictDay(e, nd)) continue;\n            if (inc[nd][u] + 1 > deg[u] - 1) continue;\n            if (inc[nd][v] + 1 > deg[v] - 1) continue;\n            basicMove(e, nd);\n            return true;\n        }\n        return false;\n    };\n\n    int moveBudget = 2500;\n    while (moveBudget-- > 0 && elapsedSec() < TIME_END) {\n        bool anyDisconnected = false;\n        for (int d = 0; d < D; d++) {\n            int cc = compCountForDay(d);\n            if (cc <= 1) continue;\n            anyDisconnected = true;\n\n            vector<int> cand;\n            cand.reserve(inDay[d].size());\n            for (int e : inDay[d]) if (comp[edges[e].u] != comp[edges[e].v]) cand.push_back(e);\n\n            if (cand.empty()) {\n                int bestE = -1;\n                long double bestI = 1e100L;\n                for (int e : inDay[d]) if (edges[e].imp < bestI) bestI = edges[e].imp, bestE = e;\n                if (bestE != -1) tryMoveEdgeToSomeDay(bestE, d);\n                break;\n            }\n\n            sort(cand.begin(), cand.end(), [&](int a, int b){ return edges[a].imp < edges[b].imp; });\n            for (int e : cand) {\n                if (tryMoveEdgeToSomeDay(e, d)) break;\n            }\n            break;\n        }\n        if (!anyDisconnected) break;\n    }\n\n    // final isolation cleanup\n    for (int rep = 0; rep < 2000; rep++) {\n        if (elapsedSec() > TIME_END) break;\n        if (!fixIsolationOnce()) break;\n    }\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (dayOfEdge[i] + 1);\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed=88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n};\n\nstruct Segment {\n    int x, y, z;\n    int axis; // 0:x 1:y 2:z\n    int len;\n};\n\nstatic inline int idx3(int D, int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nstatic long long volume_of(const vector<uint8_t>& occ) {\n    long long v = 0;\n    for (auto c : occ) v += (c != 0);\n    return v;\n}\n\nstatic uint64_t fnv1a64(const string& s, uint64_t h=1469598103934665603ull) {\n    for (unsigned char c : s) { h ^= (uint64_t)c; h *= 1099511628211ull; }\n    return h;\n}\nstatic uint64_t hash_occ(const vector<uint8_t>& occ) {\n    uint64_t h = 1469598103934665603ull;\n    for (uint8_t b : occ) {\n        h ^= (uint64_t)(b + 1);\n        h *= 1099511628211ull;\n        h ^= (h >> 32);\n    }\n    return h;\n}\n\nstatic int max_run_len_any_axis(int D, const vector<uint8_t>& occ) {\n    int best = 0;\n    // x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !occ[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && occ[idx3(D,x,y,z)]) x++;\n            best = max(best, x-s);\n        }\n    }\n    // y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !occ[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && occ[idx3(D,x,y,z)]) y++;\n            best = max(best, y-s);\n        }\n    }\n    // z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !occ[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && occ[idx3(D,x,y,z)]) z++;\n            best = max(best, z-s);\n        }\n    }\n    return best;\n}\n\n// ---- silhouette data ----\nstruct SilInfo {\n    vector<uint8_t> allow; // D^3\n    vector<vector<int>> X, Y; // per z\n    int maxVol;\n};\n\nstatic SilInfo build_allow(int D, const vector<string>& f, const vector<string>& r) {\n    SilInfo si;\n    si.allow.assign(D*D*D, 0);\n    si.X.assign(D, {});\n    si.Y.assign(D, {});\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) if (f[z][x] == '1') si.X[z].push_back(x);\n        for (int y = 0; y < D; y++) if (r[z][y] == '1') si.Y[z].push_back(y);\n        for (int x : si.X[z]) for (int y : si.Y[z]) si.allow[idx3(D,x,y,z)] = 1;\n    }\n    si.maxVol = (int)volume_of(si.allow);\n    return si;\n}\n\n// stable representative per z\nstatic vector<int> choose_stable_sequence(const vector<vector<int>>& opts) {\n    int D = (int)opts.size();\n    vector<vector<int>> par(D);\n    vector<long long> dp_prev, dp_cur;\n\n    dp_prev.assign(opts[0].size(), 0);\n    par[0].assign(opts[0].size(), -1);\n\n    for (int z = 1; z < D; z++) {\n        dp_cur.assign(opts[z].size(), LLONG_MIN/4);\n        par[z].assign(opts[z].size(), -1);\n        for (int j = 0; j < (int)opts[z-1].size(); j++) {\n            for (int k = 0; k < (int)opts[z].size(); k++) {\n                long long cand = dp_prev[j] + (opts[z][k] == opts[z-1][j] ? 1 : 0);\n                if (cand > dp_cur[k]) { dp_cur[k] = cand; par[z][k] = j; }\n            }\n        }\n        dp_prev.swap(dp_cur);\n    }\n    int bestk = 0;\n    for (int k=1;k<(int)dp_prev.size();k++) if (dp_prev[k] > dp_prev[bestk]) bestk = k;\n\n    vector<int> seq(D);\n    int cur = bestk;\n    for (int z=D-1;z>=0;z--) {\n        seq[z] = opts[z][cur];\n        cur = par[z][cur];\n        if (z==0) break;\n    }\n    return seq;\n}\n\nstatic int choose_global_hub(const vector<vector<int>>& opts, int D) {\n    vector<int> freq(D, 0);\n    for (auto &v : opts) for (int a : v) freq[a]++;\n    int best = 0;\n    for (int i=1;i<D;i++) if (freq[i] > freq[best]) best = i;\n    return best;\n}\n\n// ---- base constructions ----\n\nstatic vector<uint8_t> build_dense(int D, const SilInfo& si) {\n    return si.allow;\n}\n\n// Strict minimal per slice: max(|Xz|,|Yz|)\nstatic vector<uint8_t> build_min_edgecover(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D, 0);\n    for (int z = 0; z < D; z++) {\n        const auto& xs = si.X[z];\n        const auto& ys = si.Y[z];\n        int nx = (int)xs.size(), ny = (int)ys.size();\n        if (nx >= ny) {\n            for (int j = 0; j < ny; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n            for (int j = ny; j < nx; j++) occ[idx3(D, xs[j], ys[0], z)] = 1;\n        } else {\n            for (int j = 0; j < nx; j++) occ[idx3(D, xs[j], ys[j], z)] = 1;\n            for (int j = nx; j < ny; j++) occ[idx3(D, xs[0], ys[j], z)] = 1;\n        }\n    }\n    return occ;\n}\n\n// star with stable hubs (often good)\nstatic vector<uint8_t> build_star_stable(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D, 0);\n    vector<int> x0 = choose_stable_sequence(si.X);\n    vector<int> y0 = choose_stable_sequence(si.Y);\n    for (int z = 0; z < D; z++) {\n        for (int x : si.X[z]) occ[idx3(D, x, y0[z], z)] = 1;\n        for (int y : si.Y[z]) occ[idx3(D, x0[z], y, z)] = 1;\n    }\n    return occ;\n}\n\nstatic vector<uint8_t> build_star_globalhub(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D, 0);\n    int gx = choose_global_hub(si.X, D);\n    int gy = choose_global_hub(si.Y, D);\n    for (int z=0; z<D; z++) {\n        int xhub = gx, yhub = gy;\n        if (find(si.X[z].begin(), si.X[z].end(), xhub) == si.X[z].end()) xhub = si.X[z][0];\n        if (find(si.Y[z].begin(), si.Y[z].end(), yhub) == si.Y[z].end()) yhub = si.Y[z][0];\n        for (int x : si.X[z]) occ[idx3(D, x, yhub, z)] = 1;\n        for (int y : si.Y[z]) occ[idx3(D, xhub, y, z)] = 1;\n    }\n    return occ;\n}\n\n// continuity-biased edgecover (good for long runs)\nstatic vector<uint8_t> build_continuity_edgecover(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D, 0);\n    vector<vector<int>> W(D, vector<int>(D, 0));\n    for (int z=0; z<D; z++) for (int x : si.X[z]) for (int y : si.Y[z]) W[x][y]++;\n\n    vector<vector<uint8_t>> prevEdge(D, vector<uint8_t>(D, 0));\n    const int BONUS = 1000;\n\n    for (int z=0; z<D; z++) {\n        const auto& xs = si.X[z];\n        const auto& ys = si.Y[z];\n        int nx = (int)xs.size(), ny = (int)ys.size();\n\n        vector<uint8_t> coveredX(D, 0), coveredY(D, 0);\n        vector<pair<int,int>> edges;\n\n        auto score = [&](int x,int y)->int { return W[x][y] + (prevEdge[x][y] ? BONUS : 0); };\n\n        if (nx >= ny) {\n            for (int x : xs) {\n                int besty = ys[0], bests = -1;\n                for (int y : ys) { int s = score(x,y); if (s > bests) { bests=s; besty=y; } }\n                edges.push_back({x,besty});\n                coveredX[x]=1; coveredY[besty]=1;\n            }\n            for (int y : ys) if (!coveredY[y]) {\n                int bestx = xs[0], bests=-1;\n                for (int x : xs) { int s=score(x,y); if (s>bests) { bests=s; bestx=x; } }\n                edges.push_back({bestx,y});\n            }\n        } else {\n            for (int y : ys) {\n                int bestx = xs[0], bests=-1;\n                for (int x : xs) { int s=score(x,y); if (s>bests) { bests=s; bestx=x; } }\n                edges.push_back({bestx,y});\n                coveredX[bestx]=1; coveredY[y]=1;\n            }\n            for (int x : xs) if (!coveredX[x]) {\n                int besty = ys[0], bests=-1;\n                for (int y : ys) { int s=score(x,y); if (s>bests) { bests=s; besty=y; } }\n                edges.push_back({x,besty});\n            }\n        }\n\n        vector<vector<uint8_t>> curEdge(D, vector<uint8_t>(D, 0));\n        for (auto [x,y] : edges) {\n            occ[idx3(D,x,y,z)] = 1;\n            curEdge[x][y] = 1;\n        }\n        prevEdge.swap(curEdge);\n    }\n    return occ;\n}\n\n// New: global maximum weight matching to pick a stable x->y relation maximizing allowed overlap across z.\nstatic vector<uint8_t> build_global_matching_edgecover(int D, const SilInfo& si) {\n    vector<vector<int>> w(D, vector<int>(D, 0));\n    for (int z=0; z<D; z++) {\n        for (int x : si.X[z]) for (int y : si.Y[z]) w[x][y]++;\n    }\n\n    // DP assignment: dp[mask] for assigning first i=popcount(mask) x's to y in mask\n    int N = D;\n    vector<int> dp(1<<N, -1e9), par(1<<N, -1), parY(1<<N, -1);\n    dp[0] = 0;\n    for (int mask=0; mask<(1<<N); mask++) {\n        int i = __builtin_popcount((unsigned)mask);\n        if (i >= N) continue;\n        int cur = dp[mask];\n        if (cur < -1000000) continue;\n        for (int y=0; y<N; y++) if (!(mask & (1<<y))) {\n            int nmask = mask | (1<<y);\n            int val = cur + w[i][y];\n            if (val > dp[nmask]) {\n                dp[nmask] = val;\n                par[nmask] = mask;\n                parY[nmask] = y;\n            }\n        }\n    }\n    vector<int> perm(N, 0), inv(N, 0);\n    int mask = (1<<N)-1;\n    for (int x=N-1; x>=0; x--) {\n        int y = parY[mask];\n        perm[x] = y;\n        mask = par[mask];\n    }\n    for (int x=0;x<N;x++) inv[perm[x]] = x;\n\n    vector<uint8_t> occ(D*D*D, 0);\n\n    auto best_y_for_xz = [&](int x, int z)->int{\n        // choose y in Y[z] maximizing w[x][y]\n        int besty = si.Y[z][0], bests = -1;\n        for (int y : si.Y[z]) {\n            int s = w[x][y];\n            if (s > bests) { bests=s; besty=y; }\n        }\n        return besty;\n    };\n    auto best_x_for_yz = [&](int y, int z)->int{\n        int bestx = si.X[z][0], bests = -1;\n        for (int x : si.X[z]) {\n            int s = w[x][y];\n            if (s > bests) { bests=s; bestx=x; }\n        }\n        return bestx;\n    };\n\n    for (int z=0; z<D; z++) {\n        // cover all x\n        for (int x : si.X[z]) {\n            int y = perm[x];\n            // if not allowed this z, choose best fallback y\n            bool ok = false;\n            // (y in Y[z]?) check by allow mask\n            if (si.allow[idx3(D,x,y,z)]) ok = true;\n            if (!ok) y = best_y_for_xz(x,z);\n            occ[idx3(D,x,y,z)] = 1;\n        }\n        // cover all y\n        for (int y : si.Y[z]) {\n            bool covered = false;\n            // quick check: any x in X[z] already placed at this y?\n            for (int x : si.X[z]) {\n                if (occ[idx3(D,x,y,z)]) { covered = true; break; }\n            }\n            if (covered) continue;\n            int x = inv[y];\n            if (!si.allow[idx3(D,x,y,z)]) x = best_x_for_yz(y,z);\n            occ[idx3(D,x,y,z)] = 1;\n        }\n    }\n    return occ;\n}\n\n// ---- volume tuning by columns (structure-preserving), improved ranking ----\nstatic vector<uint8_t> fill_to_target_by_columns(\n    int D,\n    const SilInfo& si,\n    const vector<uint8_t>& base,\n    int targetV,\n    XorShift& rng\n) {\n    vector<uint8_t> occ = base;\n    int baseV = (int)volume_of(occ);\n    if (targetV <= baseV) return occ;\n    targetV = min(targetV, si.maxVol);\n\n    struct Col { int maxConsec; int cnt; int x,y; uint64_t tie; };\n    vector<Col> cols;\n    cols.reserve(D*D);\n\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int cnt = 0;\n        int bestRun = 0;\n        int run = 0;\n        for (int z=0; z<D; z++) {\n            if (si.allow[idx3(D,x,y,z)]) {\n                cnt++;\n                run++;\n                bestRun = max(bestRun, run);\n            } else {\n                run = 0;\n            }\n        }\n        if (cnt>0) cols.push_back({bestRun, cnt, x, y, rng.next_u64()});\n    }\n\n    sort(cols.begin(), cols.end(), [&](const Col& a, const Col& b){\n        if (a.maxConsec != b.maxConsec) return a.maxConsec > b.maxConsec;\n        if (a.cnt != b.cnt) return a.cnt > b.cnt;\n        return a.tie < b.tie;\n    });\n\n    int curV = baseV;\n    for (auto &c : cols) {\n        if (curV >= targetV) break;\n        for (int z=0; z<D && curV < targetV; z++) {\n            int id = idx3(D,c.x,c.y,z);\n            if (si.allow[id] && !occ[id]) {\n                occ[id] = 1;\n                curV++;\n            }\n        }\n    }\n    return occ;\n}\n\n// ---- stick operations / packing ----\nstatic void remove_segment_voxels(int D, vector<uint8_t>& rem, const Segment& sg) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1;\n    else if (sg.axis==1) dy=1;\n    else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x = sg.x + dx*t;\n        int y = sg.y + dy*t;\n        int z = sg.z + dz*t;\n        rem[idx3(D,x,y,z)] = 0;\n    }\n}\n\nstatic vector<Segment> extract_segments_axis(int D, const vector<uint8_t>& occ, int axis) {\n    vector<Segment> segs;\n    if (axis==0) {\n        for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n            int x=0;\n            while (x<D) {\n                while (x<D && !occ[idx3(D,x,y,z)]) x++;\n                int s=x;\n                while (x<D && occ[idx3(D,x,y,z)]) x++;\n                int len = x-s;\n                if (len) segs.push_back({s,y,z,0,len});\n            }\n        }\n    } else if (axis==1) {\n        for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n            int y=0;\n            while (y<D) {\n                while (y<D && !occ[idx3(D,x,y,z)]) y++;\n                int s=y;\n                while (y<D && occ[idx3(D,x,y,z)]) y++;\n                int len = y-s;\n                if (len) segs.push_back({x,s,z,1,len});\n            }\n        }\n    } else {\n        for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n            int z=0;\n            while (z<D) {\n                while (z<D && !occ[idx3(D,x,y,z)]) z++;\n                int s=z;\n                while (z<D && occ[idx3(D,x,y,z)]) z++;\n                int len = z-s;\n                if (len) segs.push_back({x,y,s,2,len});\n            }\n        }\n    }\n    return segs;\n}\n\n// Find all maximum-length segments over all axes in rem.\nstatic void find_max_segments(int D, const vector<uint8_t>& rem, int &maxLen, vector<Segment>& bestSegs) {\n    maxLen = 0;\n    bestSegs.clear();\n    auto consider = [&](int x,int y,int z,int axis,int len){\n        if (len<=0) return;\n        if (len>maxLen) { maxLen=len; bestSegs.clear(); }\n        if (len==maxLen) bestSegs.push_back({x,y,z,axis,len});\n    };\n    // x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !rem[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && rem[idx3(D,x,y,z)]) x++;\n            consider(s,y,z,0,x-s);\n        }\n    }\n    // y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !rem[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && rem[idx3(D,x,y,z)]) y++;\n            consider(x,s,z,1,y-s);\n        }\n    }\n    // z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !rem[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && rem[idx3(D,x,y,z)]) z++;\n            consider(x,y,s,2,z-s);\n        }\n    }\n}\n\n// Mixed-axis: repeatedly take a maximum-length segment (tie-break by axis bias).\nstatic vector<Segment> partition_into_sticks_mixed(int D, const vector<uint8_t>& occ, array<int,3> axisBias, XorShift& rng) {\n    vector<uint8_t> rem = occ;\n    vector<Segment> res;\n    res.reserve((int)volume_of(occ));\n\n    while (true) {\n        bool any=false;\n        for (auto v: rem) if (v) { any=true; break; }\n        if (!any) break;\n\n        int maxLen;\n        vector<Segment> best;\n        find_max_segments(D, rem, maxLen, best);\n        if (maxLen<=0 || best.empty()) break;\n\n        long long tot=0;\n        for (auto &s: best) tot += axisBias[s.axis];\n        long long r = (long long)(rng.next_u64() % (uint64_t)tot);\n        int pick=0;\n        for (int i=0;i<(int)best.size();i++) {\n            r -= axisBias[best[i].axis];\n            if (r<0) { pick=i; break; }\n        }\n        Segment chosen = best[pick];\n        res.push_back(chosen);\n        remove_segment_voxels(D, rem, chosen);\n    }\n    return res;\n}\n\n// Optimal splitting of a segment of length L under max part length cap:\n// m = ceil(L/cap), split into sizes as equal as possible (minimizes sum 1/size).\nstatic void split_segment_optimal_to_cap(const Segment& sg, int cap, vector<Segment>& out) {\n    if (sg.len <= cap) { out.push_back(sg); return; }\n    int L = sg.len;\n    int m = (L + cap - 1) / cap;\n    int a = L / m;         // floor\n    int rem = L % m;       // number of parts with size a+1\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1;\n    else if (sg.axis==1) dy=1;\n    else dz=1;\n\n    int off = 0;\n    for (int i=0;i<m;i++) {\n        int len = a + (i < rem ? 1 : 0);\n        Segment part = sg;\n        part.x += dx*off;\n        part.y += dy*off;\n        part.z += dz*off;\n        part.len = len;\n        out.push_back(part);\n        off += len;\n    }\n}\n\nstatic void presplit_optimal_to_cap(vector<Segment>& sticks, int cap) {\n    if (cap <= 0) return;\n    vector<Segment> out;\n    out.reserve(sticks.size()*2);\n    for (auto &sg : sticks) split_segment_optimal_to_cap(sg, cap, out);\n    sticks.swap(out);\n}\n\nstatic bool find_best_segment_for_length(int D, const vector<uint8_t>& rem, int L, XorShift& rng, Segment& out) {\n    int bestEx = INT_MAX;\n    vector<Segment> cand;\n    auto consider = [&](int x,int y,int z,int axis,int len){\n        if (len < L) return;\n        int ex = len - L;\n        if (ex < bestEx) { bestEx = ex; cand.clear(); }\n        if (ex == bestEx) cand.push_back({x,y,z,axis,L});\n    };\n    // x\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !rem[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && rem[idx3(D,x,y,z)]) x++;\n            consider(s,y,z,0,x-s);\n        }\n    }\n    // y\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !rem[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && rem[idx3(D,x,y,z)]) y++;\n            consider(x,s,z,1,y-s);\n        }\n    }\n    // z\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !rem[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && rem[idx3(D,x,y,z)]) z++;\n            consider(x,y,s,2,z-s);\n        }\n    }\n    if (cand.empty()) return false;\n    out = cand[rng.next_int((int)cand.size())];\n    return true;\n}\n\nstatic bool pack_sticks_into_large_once(int D,\n                                       const vector<uint8_t>& occLarge,\n                                       const vector<Segment>& need,\n                                       XorShift& rng,\n                                       vector<Segment>& placed,\n                                       int& failLen) {\n    vector<uint8_t> rem = occLarge;\n    int m = (int)need.size();\n    placed.assign(m, {0,0,0,0,0});\n\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int i,int j){\n        if (need[i].len != need[j].len) return need[i].len > need[j].len;\n        return i < j;\n    });\n\n    for (int idx : ord) {\n        int L = need[idx].len;\n        Segment best;\n        if (!find_best_segment_for_length(D, rem, L, rng, best)) {\n            failLen = L;\n            return false;\n        }\n        placed[idx] = best;\n        remove_segment_voxels(D, rem, best);\n    }\n    failLen = 0;\n    return true;\n}\n\nstatic bool pack_sticks_into_large_retry(int D,\n                                        const vector<uint8_t>& occLarge,\n                                        const vector<Segment>& need,\n                                        XorShift& rng,\n                                        vector<Segment>& placed,\n                                        int& failLen,\n                                        int retries) {\n    int bestFail = 0;\n    for (int t=0;t<retries;t++) {\n        XorShift rr(rng.next_u64());\n        vector<Segment> tmp;\n        int fl=0;\n        if (pack_sticks_into_large_once(D, occLarge, need, rr, tmp, fl)) {\n            placed.swap(tmp);\n            failLen = 0;\n            return true;\n        }\n        bestFail = max(bestFail, fl);\n    }\n    failLen = bestFail;\n    return false;\n}\n\nstatic long double penalty_sum_inv(const vector<Segment>& sticks) {\n    long double s = 0.0L;\n    for (auto &sg : sticks) s += 1.0L / (long double)sg.len;\n    return s;\n}\n\nstatic bool split_one_stick_balanced(vector<Segment>& sticks, int targetLen, int cap) {\n    int pos = -1;\n    for (int i=0;i<(int)sticks.size();i++) {\n        if (sticks[i].len == targetLen && sticks[i].len >= 2) { pos = i; break; }\n    }\n    if (pos == -1) {\n        int best=-1;\n        for (int i=0;i<(int)sticks.size();i++) if (sticks[i].len>=2) {\n            if (best==-1 || sticks[i].len > sticks[best].len) best=i;\n        }\n        pos = best;\n    }\n    if (pos==-1) return false;\n\n    Segment orig = sticks[pos];\n    int L = orig.len;\n    if (L < 2) return false;\n\n    int a = L/2, b = L-a;\n\n    if (a > cap || b > cap) {\n        int m = (L + cap - 1) / cap;\n        int base = L / m;\n        int rem = L % m;\n        int part = base + (rem ? 1 : 0);\n        part = min(part, cap);\n        a = part;\n        b = L - a;\n        if (b <= 0) return false;\n        if (b > cap) { a = cap; b = L-cap; }\n    }\n\n    Segment s1 = orig; s1.len = a;\n    Segment s2 = orig; s2.len = b;\n    if (orig.axis==0) s2.x += a;\n    else if (orig.axis==1) s2.y += a;\n    else s2.z += a;\n\n    sticks[pos] = s1;\n    sticks.push_back(s2);\n    return true;\n}\n\nstatic void fill_segment_id(int D, vector<int>& b, const Segment& sg, int id) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1;\n    else if (sg.axis==1) dy=1;\n    else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x = sg.x + dx*t;\n        int y = sg.y + dy*t;\n        int z = sg.z + dz*t;\n        b[idx3(D,x,y,z)] = id;\n    }\n}\n\n// ---- candidates ----\nstruct Cand {\n    vector<uint8_t> occ;\n    int vol;\n    int maxRun;\n    uint64_t h;\n};\n\nstatic vector<Cand> gen_candidates(int D, const SilInfo& si, XorShift& rng) {\n    vector<Cand> all;\n    unordered_set<uint64_t> seen;\n\n    auto add = [&](vector<uint8_t> occ) {\n        uint64_t h = hash_occ(occ);\n        if (!seen.insert(h).second) return;\n        int v = (int)volume_of(occ);\n        int mr = max_run_len_any_axis(D, occ);\n        all.push_back(Cand{move(occ), v, mr, h});\n    };\n\n    auto occMin   = build_min_edgecover(D, si);\n    auto occCont  = build_continuity_edgecover(D, si);\n    auto occMatch = build_global_matching_edgecover(D, si);\n    auto occStar  = build_star_stable(D, si);\n    auto occGStar = build_star_globalhub(D, si);\n    auto occDense = build_dense(D, si);\n\n    add(occMin);\n    add(occCont);\n    add(occMatch);\n    add(occStar);\n    add(occGStar);\n    add(occDense);\n\n    int minV = (int)volume_of(occMin);\n    int maxV = si.maxVol;\n\n    vector<vector<uint8_t>> bases = {occMin, occCont, occMatch, occStar};\n    vector<double> ratios = {0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.78, 0.90, 0.96};\n\n    for (auto &base : bases) {\n        int baseV = (int)volume_of(base);\n        for (double rr : ratios) {\n            int target = minV + (int)llround((maxV - minV) * rr);\n            target = max(target, baseV);\n            XorShift rrng(rng.next_u64() ^ (uint64_t)(target*2654435761u + baseV*97531u));\n            add(fill_to_target_by_columns(D, si, base, target, rrng));\n        }\n    }\n\n    // compact selection: volume quantiles, tie by maxRun\n    sort(all.begin(), all.end(), [&](const Cand& a, const Cand& b){\n        if (a.vol != b.vol) return a.vol < b.vol;\n        return a.maxRun > b.maxRun;\n    });\n\n    const int KEEP = 28;\n    vector<Cand> filtered;\n    filtered.reserve(KEEP);\n\n    for (int t=0;t<KEEP;t++) {\n        int desired = minV + (int)llround((long double)(maxV - minV) * t / max(1, KEEP-1));\n        int bestIdx=-1, bestDist=INT_MAX, bestMR=-1;\n        for (int i=0;i<(int)all.size();i++) {\n            int dist = abs(all[i].vol - desired);\n            if (dist < bestDist || (dist==bestDist && all[i].maxRun > bestMR)) {\n                bestDist=dist; bestMR=all[i].maxRun; bestIdx=i;\n            }\n        }\n        if (bestIdx!=-1) {\n            bool ok=true;\n            for (auto &c: filtered) if (c.h==all[bestIdx].h) { ok=false; break; }\n            if (ok) filtered.push_back(all[bestIdx]);\n        }\n    }\n\n    // ensure min and dense included\n    for (auto &c : all) if (c.vol == minV) {\n        bool ok=true;\n        for (auto &d: filtered) if (d.h==c.h) { ok=false; break; }\n        if (ok) filtered.push_back(c);\n        break;\n    }\n    for (auto &c : all) if (c.vol == maxV) {\n        bool ok=true;\n        for (auto &d: filtered) if (d.h==c.h) { ok=false; break; }\n        if (ok) filtered.push_back(c);\n        break;\n    }\n\n    sort(filtered.begin(), filtered.end(), [&](const Cand& a, const Cand& b){\n        if (a.vol != b.vol) return a.vol < b.vol;\n        return a.maxRun > b.maxRun;\n    });\n    return filtered;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n    vector<string> f[2], r[2];\n    for (int i=0;i<2;i++) {\n        f[i].resize(D);\n        r[i].resize(D);\n        for (int z=0;z<D;z++) cin >> f[i][z];\n        for (int z=0;z<D;z++) cin >> r[i][z];\n    }\n\n    auto t_start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n    const double TIME_LIMIT = 5.85;\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)D; seed *= 1099511628211ull;\n    for (int i=0;i<2;i++) {\n        for (int z=0;z<D;z++) seed = fnv1a64(f[i][z], seed);\n        for (int z=0;z<D;z++) seed = fnv1a64(r[i][z], seed);\n    }\n    XorShift rng(seed);\n\n    SilInfo si[2] = { build_allow(D, f[0], r[0]), build_allow(D, f[1], r[1]) };\n\n    vector<Cand> C[2] = { gen_candidates(D, si[0], rng), gen_candidates(D, si[1], rng) };\n\n    struct PairInfo { int i,j,diff; };\n    vector<PairInfo> pairs;\n    pairs.reserve(C[0].size()*C[1].size());\n    for (int i=0;i<(int)C[0].size();i++) for (int j=0;j<(int)C[1].size();j++) {\n        pairs.push_back({i,j, abs(C[0][i].vol - C[1][j].vol)});\n    }\n    sort(pairs.begin(), pairs.end(), [&](const PairInfo& a, const PairInfo& b){\n        return a.diff < b.diff;\n    });\n\n    struct BestPlan {\n        long double cost = 1e100L;\n        int ci0=-1, ci1=-1;\n        int smallObj=-1;\n        vector<Segment> sharedSmall;\n        vector<Segment> sharedLarge;\n    } best;\n\n    auto try_pair = [&](int ci0, int ci1) {\n        const auto& occ0 = C[0][ci0].occ;\n        const auto& occ1 = C[1][ci1].occ;\n        int v0 = C[0][ci0].vol, v1 = C[1][ci1].vol;\n        int diff = abs(v0 - v1);\n        if ((long double)diff >= best.cost) return;\n\n        int smallObj = (v0 <= v1 ? 0 : 1);\n        int largeObj = 1 - smallObj;\n\n        const auto& occSmall = (smallObj==0 ? occ0 : occ1);\n        const auto& occLarge = (largeObj==0 ? occ0 : occ1);\n\n        int cap = max_run_len_any_axis(D, occLarge);\n        cap = max(1, cap);\n\n        int trials = 10;\n        if (diff == 0) trials = 26;\n        else if (diff <= D*D) trials = 18;\n        else if (diff <= 2*D*D) trials = 14;\n\n        for (int t=0; t<trials && elapsed() < TIME_LIMIT; t++) {\n            vector<Segment> sticks;\n            if (t % 5 == 0) sticks = extract_segments_axis(D, occSmall, 2);        // z\n            else if (t % 5 == 1) sticks = extract_segments_axis(D, occSmall, 0);   // x\n            else if (t % 5 == 2) sticks = extract_segments_axis(D, occSmall, 1);   // y\n            else {\n                array<int,3> bias = {1,1,1};\n                int mode = rng.next_int(6);\n                if (mode==0) bias = {3,1,1};\n                else if (mode==1) bias = {1,3,1};\n                else if (mode==2) bias = {1,1,3};\n                else if (mode==3) bias = {2,1,2};\n                else if (mode==4) bias = {2,2,1};\n                else bias = {1,2,2};\n                XorShift rr(rng.next_u64());\n                sticks = partition_into_sticks_mixed(D, occSmall, bias, rr);\n            }\n\n            presplit_optimal_to_cap(sticks, cap);\n\n            vector<Segment> placed;\n            int failLen = 0;\n            int splitCnt = 0;\n            bool ok = false;\n\n            while (elapsed() < TIME_LIMIT) {\n                XorShift pr(rng.next_u64());\n                if (pack_sticks_into_large_retry(D, occLarge, sticks, pr, placed, failLen, 4)) {\n                    ok = true;\n                    break;\n                }\n                if (failLen <= 1) { ok = false; break; }\n                if (!split_one_stick_balanced(sticks, failLen, cap)) { ok = false; break; }\n                if (++splitCnt > 1200) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            long double pen = penalty_sum_inv(sticks);\n            long double cost = (long double)diff + pen;\n            if (cost < best.cost) {\n                best.cost = cost;\n                best.ci0 = ci0; best.ci1 = ci1;\n                best.smallObj = smallObj;\n                best.sharedSmall = sticks;\n                best.sharedLarge = placed;\n            }\n        }\n    };\n\n    int PAIR_LIMIT = 220;\n    for (int k=0;k<(int)pairs.size() && k<PAIR_LIMIT && elapsed()<TIME_LIMIT;k++) {\n        if ((long double)pairs[k].diff >= best.cost) break;\n        try_pair(pairs[k].i, pairs[k].j);\n    }\n    for (int k=PAIR_LIMIT;k<(int)pairs.size() && k<PAIR_LIMIT+80 && elapsed()<TIME_LIMIT;k++) {\n        if ((long double)pairs[k].diff >= best.cost) break;\n        try_pair(pairs[k].i, pairs[k].j);\n    }\n\n    // Fallback: dense+unit (should never happen)\n    if (best.smallObj == -1) {\n        vector<int> b0(D*D*D,0), b1(D*D*D,0);\n        int n=0;\n        for (int i=0;i<2;i++) {\n            const auto& A = si[i].allow;\n            for (int x=0;x<D;x++) for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n                int id = idx3(D,x,y,z);\n                if (A[id]) { n++; if (i==0) b0[id]=n; else b1[id]=n; }\n            }\n        }\n        cout << n << \"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b0[i]; } cout<<\"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b1[i]; } cout<<\"\\n\";\n        return 0;\n    }\n\n    const auto& occ0 = C[0][best.ci0].occ;\n    const auto& occ1 = C[1][best.ci1].occ;\n\n    int smallObj = best.smallObj;\n    int largeObj = 1 - smallObj;\n\n    const auto& occLarge = (largeObj==0 ? occ0 : occ1);\n\n    // leftover in large\n    vector<uint8_t> remLarge = occLarge;\n    for (auto &sg : best.sharedLarge) remove_segment_voxels(D, remLarge, sg);\n\n    // partition leftover into sticks (z then x then y to cover any gaps)\n    vector<Segment> uniqueLarge = extract_segments_axis(D, remLarge, 2);\n    for (auto &sg : uniqueLarge) remove_segment_voxels(D, remLarge, sg);\n    auto ux = extract_segments_axis(D, remLarge, 0);\n    for (auto &sg : ux) remove_segment_voxels(D, remLarge, sg);\n    auto uy = extract_segments_axis(D, remLarge, 1);\n    for (auto &sg : uy) remove_segment_voxels(D, remLarge, sg);\n    uniqueLarge.insert(uniqueLarge.end(), ux.begin(), ux.end());\n    uniqueLarge.insert(uniqueLarge.end(), uy.begin(), uy.end());\n\n    int m = (int)best.sharedSmall.size();\n    int u = (int)uniqueLarge.size();\n    int n = m + u;\n\n    vector<int> bA(D*D*D, 0), bB(D*D*D, 0); // object0, object1\n\n    int curId = 1;\n    for (int i=0;i<m;i++,curId++) {\n        if (smallObj == 0) {\n            fill_segment_id(D, bA, best.sharedSmall[i], curId);\n            fill_segment_id(D, bB, best.sharedLarge[i], curId);\n        } else {\n            fill_segment_id(D, bB, best.sharedSmall[i], curId);\n            fill_segment_id(D, bA, best.sharedLarge[i], curId);\n        }\n    }\n    for (int i=0;i<u;i++,curId++) {\n        if (largeObj == 0) fill_segment_id(D, bA, uniqueLarge[i], curId);\n        else fill_segment_id(D, bB, uniqueLarge[i], curId);\n    }\n\n    cout << n << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << bA[i]; }\n    cout << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << bB[i]; }\n    cout << \"\\n\";\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstatic inline int ceil_sqrt_ll(long long x) {\n    if (x <= 0) return 0;\n    long long r = (long long)floor(sqrt((long double)x));\n    while (r * r < x) ++r;\n    while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n    return (int)r;\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool merge(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// xorshift64 RNG\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Connector {\n    int N, M;\n    vector<Edge> edges;\n    vector<vector<tuple<int,long long,int>>> g; // to, w, edgeId\n\n    vector<vector<long long>> dist;\n    vector<vector<int>> prevV, prevE;\n\n    vector<int> usedStamp;\n    int stamp = 1;\n\n    vector<int> remStamp;\n    int remCurStamp = 1;\n\n    Connector(int N_, int M_, const vector<Edge>& e): N(N_), M(M_), edges(e),\n        g(N), dist(N, vector<long long>(N, (1LL<<62))),\n        prevV(N, vector<int>(N, -1)), prevE(N, vector<int>(N, -1)),\n        usedStamp(M, 0), remStamp(M, 0) {\n\n        for (int i = 0; i < M; i++) {\n            g[edges[i].u].push_back({edges[i].v, edges[i].w, i});\n            g[edges[i].v].push_back({edges[i].u, edges[i].w, i});\n        }\n        all_pairs_dijkstra();\n    }\n\n    void all_pairs_dijkstra() {\n        for (int s = 0; s < N; s++) {\n            auto &ds = dist[s];\n            auto &pv = prevV[s];\n            auto &pe = prevE[s];\n            fill(ds.begin(), ds.end(), (1LL<<62));\n            fill(pv.begin(), pv.end(), -1);\n            fill(pe.begin(), pe.end(), -1);\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            ds[s] = 0; pv[s] = s; pe[s] = -1;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [dcur, v] = pq.top(); pq.pop();\n                if (dcur != ds[v]) continue;\n                for (auto [to, w, id] : g[v]) {\n                    long long nd = dcur + w;\n                    if (nd < ds[to]) {\n                        ds[to] = nd;\n                        pv[to] = v;\n                        pe[to] = id;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n        }\n    }\n\n    // Candidate edges from metric MST expansion\n    vector<int> candidate_metric_mst(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n\n        if ((int)terminals.size() <= 1) return marked;\n\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1; long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i]; v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) { key[u] = d; parent[u] = v; }\n            }\n        }\n\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        // ensure terminal reachability from 0 if something is missing\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true; dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) { reach[to] = true; dq.push_back(to); }\n            }\n        }\n        for (int t : terminals) if (!reach[t]) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        return marked;\n    }\n\n    // Candidate edges from union of shortest paths from 0\n    vector<int> candidate_root_paths(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n        for (int t : terminals) if (t != 0) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n        return marked;\n    }\n\n    pair<long long, vector<int>> prune_candidate(const vector<int>& cand, const vector<char>& isTerm, bool needEdges) {\n        if (cand.empty()) return {0LL, {}};\n\n        vector<int> candSorted = cand;\n        sort(candSorted.begin(), candSorted.end(),\n             [&](int a, int b){ return edges[a].w < edges[b].w; });\n\n        DSU dsu(N);\n        vector<int> treeEdges; treeEdges.reserve(candSorted.size());\n        for (int eid : candSorted) if (dsu.merge(edges[eid].u, edges[eid].v)) treeEdges.push_back(eid);\n\n        vector<vector<pair<int,int>>> adj(N);\n        vector<int> deg(N, 0);\n        for (int eid : treeEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            adj[u].push_back({v, eid});\n            adj[v].push_back({u, eid});\n            deg[u]++; deg[v]++;\n        }\n\n        int curRemStamp = remCurStamp++;\n        auto isRemoved = [&](int eid)->bool { return remStamp[eid] == curRemStamp; };\n        auto setRemoved = [&](int eid){ remStamp[eid] = curRemStamp; };\n\n        deque<int> q;\n        for (int i = 0; i < N; i++) if (!isTerm[i] && deg[i] == 1) q.push_back(i);\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n            int to = -1, eid = -1;\n            for (auto [nx, id] : adj[v]) if (!isRemoved(id)) { to = nx; eid = id; break; }\n            if (eid == -1) { deg[v] = 0; continue; }\n            setRemoved(eid);\n            deg[v]--; deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        long long cost = 0;\n        vector<int> remain;\n        if (needEdges) remain.reserve(treeEdges.size());\n        for (int eid : treeEdges) if (!isRemoved(eid)) {\n            cost += edges[eid].w;\n            if (needEdges) remain.push_back(eid);\n        }\n        return {cost, remain};\n    }\n\n    // Fast cost used inside SA: metric MST expansion only\n    long long steiner_cost_metric(const vector<int>& terminals) {\n        if (terminals.size() <= 1) return 0;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        auto cand = candidate_metric_mst(terminals);\n        return prune_candidate(cand, isTerm, false).first;\n    }\n\n    // Final build: choose better of metric MST vs root-path union\n    vector<char> steiner_build_best(const vector<int>& terminals) {\n        vector<char> on(M, 0);\n        if (terminals.size() <= 1) return on;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n\n        auto candA = candidate_metric_mst(terminals);\n        auto resA = prune_candidate(candA, isTerm, true);\n\n        auto candB = candidate_root_paths(terminals);\n        auto resB = prune_candidate(candB, isTerm, true);\n\n        const auto& best = (resA.first <= resB.first) ? resA : resB;\n        for (int eid : best.second) on[eid] = 1;\n        return on;\n    }\n};\n\nstruct KeyMask {\n    uint64_t a, b;\n    bool operator==(const KeyMask& o) const { return a==o.a && b==o.b; }\n};\nstruct KeyHash {\n    size_t operator()(const KeyMask& k) const {\n        uint64_t x = k.a * 11995408973635179863ULL ^ (k.b + 0x9e3779b97f4a7c15ULL);\n        x ^= x >> 33; x *= 0xff51afd7ed558ccdULL;\n        x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53ULL;\n        x ^= x >> 33;\n        return (size_t)x;\n    }\n};\n\nstruct SAState {\n    int N, K;\n    const vector<int>* dist2;                // K*N\n    const vector<array<int,100>>* order;     // K\n    Connector* conn;\n    unordered_map<KeyMask, long long, KeyHash>* edgeCache;\n\n    static constexpr int D2_LIMIT = 5000 * 5000;\n\n    vector<char> active;\n    vector<int> owner;\n    vector<int> dOwn;\n\n    vector<int> head;\n    vector<int> rprev, rnext;\n\n    vector<multiset<int>> ms;\n    vector<int> P;\n\n    long long radioCost = 0;\n    long long edgeCost = 0;\n    long long totalCost = 0;\n\n    inline int d2(int k, int i) const { return (*dist2)[k*N + i]; }\n\n    void list_remove(int k) {\n        int s = owner[k];\n        int pv = rprev[k], nx = rnext[k];\n        if (pv != -1) rnext[pv] = nx;\n        else head[s] = nx;\n        if (nx != -1) rprev[nx] = pv;\n        rprev[k] = rnext[k] = -1;\n    }\n    void list_add(int k, int s) {\n        int h = head[s];\n        head[s] = k;\n        rprev[k] = -1;\n        rnext[k] = h;\n        if (h != -1) rprev[h] = k;\n    }\n\n    vector<int> terminals() const {\n        vector<int> t; t.reserve(N);\n        t.push_back(0);\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) t.push_back(i);\n        return t;\n    }\n\n    KeyMask terminal_mask() const {\n        uint64_t a=0, b=0;\n        // include 0 always\n        a |= 1ULL;\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) {\n            if (i < 64) a |= 1ULL << i;\n            else b |= 1ULL << (i - 64);\n        }\n        return {a,b};\n    }\n\n    long long edge_cost_cached() {\n        KeyMask km = terminal_mask();\n        auto it = edgeCache->find(km);\n        if (it != edgeCache->end()) return it->second;\n        auto terms = terminals();\n        long long c = conn->steiner_cost_metric(terms);\n        (*edgeCache)[km] = c;\n        return c;\n    }\n\n    int nearest_active(int k, int ex) const {\n        for (int idx = 0; idx < N; idx++) {\n            int v = (*order)[k][idx];\n            if (!active[v]) continue;\n            if (v == ex) continue;\n            int dd = d2(k, v);\n            if (dd <= D2_LIMIT) return v;\n        }\n        return -1;\n    }\n\n    void rebuild_from_active_nearest() {\n        active[0] = 1;\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            for (int idx = 0; idx < N; idx++) {\n                int v = (*order)[k][idx];\n                if (active[v]) { chosen = v; break; }\n            }\n            if (chosen < 0) chosen = 0;\n            int dd = d2(k, chosen);\n            owner[k] = chosen;\n            dOwn[k] = dd;\n            list_add(k, chosen);\n            ms[chosen].insert(dd);\n        }\n\n        for (int i = 1; i < N; i++) if (ms[i].empty()) active[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    void rebuild_from_active_owner(const vector<char>& act, const vector<int>& own) {\n        active = act;\n        active[0] = 1;\n\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int s = own[k];\n            if (s < 0 || s >= N || !active[s] || d2(k, s) > D2_LIMIT) {\n                s = nearest_active(k, -1);\n                if (s < 0) s = 0;\n            }\n            owner[k] = s;\n            int dd = d2(k, s);\n            dOwn[k] = dd;\n            list_add(k, s);\n            ms[s].insert(dd);\n        }\n\n        // make sure non-empty are active\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) active[i] = 1;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    struct Log {\n        vector<tuple<int,int,int>> moved; // (resident, oldOwner, oldDist)\n        vector<pair<int,char>> flipped;   // (station, oldActive)\n        vector<pair<int,int>> oldP;       // (station, oldP)\n        vector<pair<int,char>> oldEmpty;  // (station, oldEmpty)\n        vector<int> touched;\n        vector<char> touchedFlag;\n        long long oldRadio, oldEdge, oldTotal;\n        Log(int N=0): touchedFlag(N, 0) {}\n    };\n\n    void touch_station(int s, Log& log) {\n        if (log.touchedFlag[s]) return;\n        log.touchedFlag[s] = 1;\n        log.touched.push_back(s);\n        log.oldP.push_back({s, P[s]});\n        log.oldEmpty.push_back({s, (char)ms[s].empty()});\n    }\n\n    void move_resident(int k, int newS, Log& log) {\n        int oldS = owner[k];\n        if (oldS == newS) return;\n        int oldD = dOwn[k];\n        log.moved.push_back({k, oldS, oldD});\n\n        touch_station(oldS, log);\n        touch_station(newS, log);\n\n        auto it = ms[oldS].find(oldD);\n        if (it != ms[oldS].end()) ms[oldS].erase(it);\n        int nd = d2(k, newS);\n        ms[newS].insert(nd);\n\n        list_remove(k);\n        owner[k] = newS;\n        dOwn[k] = nd;\n        list_add(k, newS);\n    }\n\n    bool apply_remove(int v, Log& log) {\n        if (v == 0 || !active[v]) return false;\n\n        log.flipped.push_back({v, active[v]});\n        active[v] = 0;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n        return true;\n    }\n\n    bool apply_add(int u, Log& log) {\n        if (active[u]) return false;\n        log.flipped.push_back({u, active[u]});\n        active[u] = 1;\n\n        // move residents who prefer u (distance, then index)\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    bool apply_swap(int v, int u, Log& log) {\n        if (v == 0 || !active[v] || active[u]) return false;\n        log.flipped.push_back({v, active[v]}); active[v] = 0;\n        log.flipped.push_back({u, active[u]}); active[u] = 1;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    void finalize(Log& log) {\n        // update radio incrementally\n        radioCost = log.oldRadio;\n        vector<int> oldpArr(N, -1);\n        vector<char> oldEmptyArr(N, 0);\n        for (auto [s, op] : log.oldP) oldpArr[s] = op;\n        for (auto [s, oe] : log.oldEmpty) oldEmptyArr[s] = oe;\n\n        bool terminalChanged = false;\n        for (int s : log.touched) {\n            int oldp = oldpArr[s];\n            int newp = 0;\n            if (!ms[s].empty()) newp = ceil_sqrt_ll(*ms[s].rbegin());\n            if (newp > 5000) newp = 5000;\n            P[s] = newp;\n            radioCost += 1LL*newp*newp - 1LL*oldp*oldp;\n            if ((bool)oldEmptyArr[s] != ms[s].empty()) terminalChanged = true;\n        }\n\n        if (terminalChanged) edgeCost = edge_cost_cached();\n        else edgeCost = log.oldEdge;\n\n        totalCost = radioCost + edgeCost;\n    }\n\n    void undo(Log& log) {\n        for (int i = (int)log.moved.size() - 1; i >= 0; i--) {\n            auto [k, oldS, oldD] = log.moved[i];\n            int curS = owner[k];\n            int curD = dOwn[k];\n\n            auto it = ms[curS].find(curD);\n            if (it != ms[curS].end()) ms[curS].erase(it);\n            ms[oldS].insert(oldD);\n\n            list_remove(k);\n            owner[k] = oldS;\n            dOwn[k] = oldD;\n            list_add(k, oldS);\n        }\n\n        for (int i = (int)log.flipped.size() - 1; i >= 0; i--) {\n            auto [s, oldA] = log.flipped[i];\n            active[s] = oldA;\n        }\n        for (auto [s, op] : log.oldP) P[s] = op;\n\n        radioCost = log.oldRadio;\n        edgeCost  = log.oldEdge;\n        totalCost = log.oldTotal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n    vector<Edge> edges(M);\n    for (int j = 0; j < M; j++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n    }\n\n    vector<int> a(K), b(K);\n    for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n    vector<int> dist2((size_t)K * N);\n    for (int k = 0; k < K; k++) for (int i = 0; i < N; i++) {\n        long long dx = (long long)x[i] - a[k];\n        long long dy = (long long)y[i] - b[k];\n        dist2[k*N + i] = (int)(dx*dx + dy*dy);\n    }\n\n    vector<array<int,100>> order(K);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) order[k][i] = i;\n        sort(order[k].begin(), order[k].end(), [&](int i, int j){\n            int di = dist2[k*N + i];\n            int dj = dist2[k*N + j];\n            if (di != dj) return di < dj;\n            return i < j;\n        });\n    }\n\n    Connector conn(N, M, edges);\n\n    unordered_map<KeyMask, long long, KeyHash> edgeCache;\n    edgeCache.reserve(1 << 14);\n\n    SAState st;\n    st.N = N; st.K = K;\n    st.dist2 = &dist2;\n    st.order = &order;\n    st.conn = &conn;\n    st.edgeCache = &edgeCache;\n\n    st.active.assign(N, 1);\n    st.rebuild_from_active_nearest();\n\n    RNG rng(123456789);\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n    const double TL = 1.90;\n\n    vector<char> bestActive = st.active;\n    vector<int> bestOwner = st.owner;\n    long long bestCost = st.totalCost;\n\n    // SA schedule (similar to the good 79.24M version)\n    const double T0 = 2e9;\n    const double T1 = 2e6;\n\n    while (elapsed() < TL) {\n        double t = elapsed() / TL;\n        double temp = T0 * pow(T1 / T0, t);\n\n        SAState::Log log(N);\n        log.oldRadio = st.radioCost;\n        log.oldEdge  = st.edgeCost;\n        log.oldTotal = st.totalCost;\n\n        double r = rng.nextDouble();\n        bool ok = false;\n\n        if (r < 0.45) { // remove\n            int v = -1;\n            for (int tries = 0; tries < 20; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (st.active[cand] && !st.ms[cand].empty()) { v = cand; break; }\n            }\n            if (v != -1) ok = st.apply_remove(v, log);\n        } else if (r < 0.80) { // add\n            int u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (!st.active[cand]) { u = cand; break; }\n            }\n            if (u != -1) ok = st.apply_add(u, log);\n        } else { // swap\n            int v = -1, u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int candV = rng.nextInt(1, N-1);\n                if (st.active[candV] && !st.ms[candV].empty()) { v = candV; break; }\n            }\n            for (int tries = 0; tries < 30; tries++) {\n                int candU = rng.nextInt(1, N-1);\n                if (!st.active[candU]) { u = candU; break; }\n            }\n            if (v != -1 && u != -1) ok = st.apply_swap(v, u, log);\n        }\n\n        if (!ok) { st.undo(log); continue; }\n\n        st.finalize(log);\n\n        long long delta = st.totalCost - log.oldTotal;\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(-(double)delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (!accept) { st.undo(log); continue; }\n\n        if (st.totalCost < bestCost) {\n            bestCost = st.totalCost;\n            bestActive = st.active;\n            bestOwner = st.owner;\n        }\n    }\n\n    // Restore best snapshot\n    st.rebuild_from_active_owner(bestActive, bestOwner);\n\n    // Small post-processing: try to relocate outlier residents greedily\n    // (short time slice)\n    const double POST_TL = 1.97;\n    while (elapsed() < POST_TL) {\n        int s = rng.nextInt(0, N-1);\n        if (s != 0 && st.ms[s].empty()) continue;\n        // pick farthest resident in station s\n        int bestK = -1;\n        int bestD = -1;\n        for (int k = st.head[s]; k != -1; k = st.rnext[k]) {\n            if (st.dOwn[k] > bestD) { bestD = st.dOwn[k]; bestK = k; }\n        }\n        if (bestK == -1) continue;\n\n        // try a few nearest stations as new owner (including currently inactive)\n        int curOwner = st.owner[bestK];\n        long long base = st.totalCost;\n        int bestT = -1;\n\n        for (int idx = 0; idx < 8; idx++) {\n            int tStation = order[bestK][idx];\n            if (tStation == curOwner) continue;\n            int dd = dist2[bestK*N + tStation];\n            if (dd > SAState::D2_LIMIT) continue;\n\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n\n            if (!st.active[tStation]) { log.flipped.push_back({tStation, st.active[tStation]}); st.active[tStation] = 1; }\n            st.move_resident(bestK, tStation, log);\n            st.finalize(log);\n\n            if (st.totalCost < base) {\n                base = st.totalCost;\n                bestT = tStation;\n            }\n            st.undo(log);\n        }\n\n        if (bestT != -1) {\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n            if (!st.active[bestT]) { log.flipped.push_back({bestT, st.active[bestT]}); st.active[bestT] = 1; }\n            st.move_resident(bestK, bestT, log);\n            st.finalize(log);\n            // keep only if improved\n            if (st.totalCost >= log.oldTotal) st.undo(log);\n        }\n    }\n\n    // Final cable set (best of two constructions, done only once)\n    vector<int> terms = st.terminals();\n    vector<char> on = conn.steiner_build_best(terms);\n\n    // Output P_1..P_N\n    for (int i = 0; i < N; i++) {\n        int pi = st.P[i];\n        if (pi < 0) pi = 0;\n        if (pi > 5000) pi = 5000;\n        cout << pi << (i+1==N?'\\n':' ');\n    }\n    // Output B_1..B_M\n    for (int j = 0; j < M; j++) {\n        cout << (int)on[j] << (j+1==M?'\\n':' ');\n    }\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int M = N * (N + 1) / 2;\nstatic constexpr int LIMIT = 10000;\n\nstatic inline int ID(int x, int y) { return x * (x + 1) / 2 + y; }\n\n// splitmix64 RNG\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstruct Precomp {\n    array<int, M> X{}, Y{};\n    array<array<int,2>, M> par{};\n    array<int, M> parCnt{};\n    array<array<int,2>, M> ch{};\n    array<int, M> chCnt{};\n\n    // downward edges (parent -> child), count = N*(N-1)=870\n    int Ecnt = 0;\n    array<int, N*(N-1)> eP{};\n    array<int, N*(N-1)> eC{};\n\n    // incident edge ids per node (<=4)\n    array<array<int,4>, M> inc{};\n    array<int, M> incCnt{};\n\n    Precomp() {\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v = ID(x,y);\n                X[v] = x; Y[v] = y;\n\n                parCnt[v] = 0;\n                if (x > 0) {\n                    if (y > 0) par[v][parCnt[v]++] = ID(x-1, y-1);\n                    if (y < x) par[v][parCnt[v]++] = ID(x-1, y);\n                }\n                chCnt[v] = 0;\n                if (x + 1 < N) {\n                    ch[v][chCnt[v]++] = ID(x+1, y);\n                    ch[v][chCnt[v]++] = ID(x+1, y+1);\n                }\n                incCnt[v] = 0;\n            }\n        }\n\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = ID(x,y);\n                for (int i = 0; i < chCnt[p]; i++) {\n                    int c = ch[p][i];\n                    int eid = Ecnt++;\n                    eP[eid] = p;\n                    eC[eid] = c;\n                    inc[p][incCnt[p]++] = eid;\n                    inc[c][incCnt[c]++] = eid;\n                }\n            }\n        }\n    }\n};\nstatic Precomp PC;\n\nstruct Params {\n    // PQ key:\n    // 0: diff only\n    // 1: diff*64 + (N-1-x_parent) (slight upper-tier preference)\n    int priorityMode = 0;\n\n    // bubble-up choice when both parents violate:\n    // 0: larger parent value, 1: smaller parent value\n    int bubbleUpMode = 0;\n\n    bool bubbleDown = true;\n    int bubbleDownLimit = -1; // -1 unlimited, else max steps\n\n    bool randomizedTies = false;\n\n    // number of top PQ candidates to consider and pick best by deltaE\n    int lookahead = 1; // 1 = classic behavior\n};\n\nstruct PQEdge {\n    int key;\n    uint32_t tie;\n    int p, c;\n    bool operator<(PQEdge const& o) const {\n        if (key != o.key) return key < o.key;\n        return tie < o.tie;\n    }\n};\n\nstruct Result {\n    int E = INT_MAX;\n    int K = INT_MAX;\n    vector<pair<int,int>> ops; // node ids\n};\n\nstatic inline bool better(const Result& A, const Result& B) {\n    if (A.E != B.E) return A.E < B.E;\n    return A.K < B.K;\n}\n\nstruct Runner {\n    array<int, M> a{};\n    int curE = 0;\n\n    priority_queue<PQEdge> pq;\n    vector<pair<int,int>> ops;\n\n    SplitMix64 rng;\n    Params P;\n    int capK = LIMIT;\n\n    Runner(uint64_t seed, Params params) : rng(seed), P(params) {}\n\n    inline bool violated_edge(int p, int c) const { return a[p] > a[c]; }\n\n    inline bool violated_eid(int eid) const {\n        return a[PC.eP[eid]] > a[PC.eC[eid]];\n    }\n\n    inline int edge_key(int p, int c) const {\n        int diff = a[p] - a[c];\n        if (P.priorityMode == 0) return diff;\n        int bonus = (N - 1 - PC.X[p]);\n        return diff * 64 + bonus;\n    }\n\n    inline void push_edge_if_viol(int p, int c) {\n        if (a[p] > a[c]) {\n            uint32_t tie = P.randomizedTies ? rng.next_u32() : 0u;\n            pq.push(PQEdge{edge_key(p,c), tie, p, c});\n        }\n    }\n\n    void init_state(const array<int,M>& initA) {\n        a = initA;\n        ops.clear();\n        while (!pq.empty()) pq.pop();\n\n        curE = 0;\n        for (int eid = 0; eid < PC.Ecnt; eid++) {\n            int p = PC.eP[eid], c = PC.eC[eid];\n            if (a[p] > a[c]) {\n                curE++;\n                push_edge_if_viol(p, c);\n            }\n        }\n    }\n\n    // compute deltaE for swapping u,v (only incident edges change). Does not modify state.\n    int eval_deltaE(int u, int v) const {\n        int touched[8], tcnt = 0;\n        auto add_eid = [&](int eid) {\n            for (int i = 0; i < tcnt; i++) if (touched[i] == eid) return;\n            touched[tcnt++] = eid;\n        };\n        for (int i = 0; i < PC.incCnt[u]; i++) add_eid(PC.inc[u][i]);\n        for (int i = 0; i < PC.incCnt[v]; i++) add_eid(PC.inc[v][i]);\n\n        int before = 0, after = 0;\n        int au = a[u], av = a[v];\n        for (int i = 0; i < tcnt; i++) {\n            int eid = touched[i];\n            int p = PC.eP[eid], c = PC.eC[eid];\n            int ap = a[p], ac = a[c];\n            if (ap > ac) before++;\n\n            // after swap, values at u and v swap\n            if (p == u) ap = av;\n            else if (p == v) ap = au;\n            if (c == u) ac = av;\n            else if (c == v) ac = au;\n\n            if (ap > ac) after++;\n        }\n        return after - before; // negative is good (reduces violations)\n    }\n\n    bool do_swap_nodes(int u, int v) {\n        // cancel consecutive identical swap\n        bool can_cancel = !ops.empty() &&\n            ((ops.back().first == u && ops.back().second == v) ||\n             (ops.back().first == v && ops.back().second == u));\n\n        if (!can_cancel) {\n            if ((int)ops.size() >= capK) return false;\n            if ((int)ops.size() >= LIMIT) return false;\n        }\n\n        // touched edges <= 8, dedup\n        int touched[8], tcnt = 0;\n        auto add_eid = [&](int eid) {\n            for (int i = 0; i < tcnt; i++) if (touched[i] == eid) return;\n            touched[tcnt++] = eid;\n        };\n        for (int i = 0; i < PC.incCnt[u]; i++) add_eid(PC.inc[u][i]);\n        for (int i = 0; i < PC.incCnt[v]; i++) add_eid(PC.inc[v][i]);\n\n        for (int i = 0; i < tcnt; i++) if (violated_eid(touched[i])) curE--;\n        swap(a[u], a[v]);\n        for (int i = 0; i < tcnt; i++) if (violated_eid(touched[i])) curE++;\n\n        // push incident edges back to PQ\n        for (int i = 0; i < tcnt; i++) {\n            int eid = touched[i];\n            push_edge_if_viol(PC.eP[eid], PC.eC[eid]);\n        }\n\n        if (can_cancel) ops.pop_back();\n        else ops.push_back({u,v});\n        return true;\n    }\n\n    void bubble_up(int u) {\n        while (true) {\n            int cc = 0;\n            int cand[2];\n            for (int i = 0; i < PC.parCnt[u]; i++) {\n                int p = PC.par[u][i];\n                if (a[p] > a[u]) cand[cc++] = p;\n            }\n            if (cc == 0) break;\n\n            int chosen = cand[0];\n            if (cc == 2) {\n                if (P.bubbleUpMode == 0) {\n                    if (a[cand[1]] > a[chosen]) chosen = cand[1];\n                } else {\n                    if (a[cand[1]] < a[chosen]) chosen = cand[1];\n                }\n                if (P.randomizedTies && a[cand[0]] == a[cand[1]]) {\n                    if (rng.next_u32() & 1u) chosen = cand[1];\n                }\n            }\n\n            if (!do_swap_nodes(chosen, u)) break;\n            u = chosen;\n        }\n    }\n\n    void bubble_down(int u) {\n        if (!P.bubbleDown) return;\n        int steps = 0;\n        while (true) {\n            if (P.bubbleDownLimit != -1 && steps >= P.bubbleDownLimit) break;\n\n            int best = -1;\n            for (int i = 0; i < PC.chCnt[u]; i++) {\n                int c = PC.ch[u][i];\n                if (a[u] > a[c]) {\n                    if (best == -1 || a[c] < a[best]) best = c;\n                    else if (P.randomizedTies && a[c] == a[best]) {\n                        if (rng.next_u32() & 1u) best = c;\n                    }\n                }\n            }\n            if (best == -1) break;\n\n            if (!do_swap_nodes(u, best)) break;\n            u = best;\n            steps++;\n        }\n    }\n\n    // pick next swap from PQ with lookahead by deltaE\n    bool pick_and_apply_one() {\n        vector<PQEdge> cand;\n        cand.reserve(P.lookahead);\n\n        while (!pq.empty() && (int)cand.size() < P.lookahead) {\n            auto e = pq.top(); pq.pop();\n            if (violated_edge(e.p, e.c)) cand.push_back(e);\n        }\n        if (cand.empty()) return false;\n\n        int bestIdx = 0;\n        int bestDelta = INT_MAX;\n        int bestKey = -1;\n\n        for (int i = 0; i < (int)cand.size(); i++) {\n            int p = cand[i].p, c = cand[i].c;\n            int d = eval_deltaE(p, c); // prefer most negative\n            if (d < bestDelta || (d == bestDelta && cand[i].key > bestKey)) {\n                bestDelta = d;\n                bestKey = cand[i].key;\n                bestIdx = i;\n            }\n        }\n\n        // push back unchosen candidates (still possibly violating)\n        for (int i = 0; i < (int)cand.size(); i++) {\n            if (i == bestIdx) continue;\n            pq.push(cand[i]);\n        }\n\n        int p = cand[bestIdx].p, c = cand[bestIdx].c;\n        if (!violated_edge(p, c)) return true; // became stale after evaluation? harmless\n        if (!do_swap_nodes(p, c)) return false;\n        bubble_up(p);\n        bubble_down(c);\n        return true;\n    }\n\n    Result run(const array<int,M>& initA) {\n        init_state(initA);\n\n        while (curE > 0) {\n            if ((int)ops.size() >= capK || (int)ops.size() >= LIMIT) break;\n            if (!pick_and_apply_one()) break;\n        }\n\n        return Result{curE, (int)ops.size(), ops};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    array<int, M> initA{};\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            int v; cin >> v;\n            initA[ID(x,y)] = v;\n        }\n    }\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n    const double TL = 1.88;\n\n    uint64_t baseSeed =\n        (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result best;\n\n    auto attempt = [&](uint64_t seed, const Params& P, int pruneMargin) {\n        Runner r(seed, P);\n        if (best.E == 0) r.capK = min(LIMIT, best.K + pruneMargin);\n        else r.capK = LIMIT;\n        Result res = r.run(initA);\n        if (better(res, best)) best = std::move(res);\n    };\n\n    // --- Deterministic baselines (fast, stable) ---\n    {\n        Params P;\n        P.priorityMode = 0;\n        P.bubbleUpMode = 0;\n        P.bubbleDown = true;\n        P.bubbleDownLimit = -1;\n        P.randomizedTies = false;\n        P.lookahead = 1; // classic\n        attempt(0, P, 0);\n    }\n    {\n        Params P;\n        P.priorityMode = 0;\n        P.bubbleUpMode = 0;\n        P.bubbleDown = true;\n        P.bubbleDownLimit = -1;\n        P.randomizedTies = false;\n        P.lookahead = 4; // deltaE lookahead\n        attempt(1, P, 0);\n    }\n    {\n        Params P;\n        P.priorityMode = 1;\n        P.bubbleUpMode = 0;\n        P.bubbleDown = true;\n        P.bubbleDownLimit = -1;\n        P.randomizedTies = false;\n        P.lookahead = 4;\n        attempt(2, P, 0);\n    }\n\n    // --- Random multi-start over a few strong variants ---\n    vector<Params> vars;\n    {\n        Params P;\n        P.priorityMode = 0; P.bubbleUpMode = 0; P.bubbleDown = true;  P.bubbleDownLimit = -1; P.randomizedTies = true; P.lookahead = 1;\n        vars.push_back(P);\n        P.lookahead = 4; vars.push_back(P);\n        P.bubbleDownLimit = 2; vars.push_back(P);\n        P.bubbleDown = false; P.bubbleDownLimit = -1; vars.push_back(P);\n        P.priorityMode = 1; P.bubbleDown = true; P.lookahead = 4; vars.push_back(P);\n        P.bubbleUpMode = 1; vars.push_back(P);\n    }\n\n    int it = 0;\n    while (elapsed() < TL) {\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)(it + 1);\n        const Params& P = vars[it % (int)vars.size()];\n        attempt(seed, P, /*pruneMargin=*/8);\n        it++;\n    }\n\n    // Output best\n    cout << best.ops.size() << \"\\n\";\n    for (auto [u,v] : best.ops) {\n        cout << PC.X[u] << \" \" << PC.Y[u] << \" \" << PC.X[v] << \" \" << PC.Y[v] << \"\\n\";\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    cin >> D >> N;\n\n    const int ei = 0, ej = (D - 1) / 2;\n    auto inside = [&](int i, int j) { return 0 <= i && i < D && 0 <= j && j < D; };\n    auto vid = [&](int i, int j) { return i * D + j; };\n    auto pos = [&](int v) { return pair<int,int>(v / D, v % D); };\n\n    const int V = D * D;\n    const int root = vid(ei, ej);\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    // Storable cells (all free cells except entrance)\n    vector<int> storableCells;\n    storableCells.reserve(V);\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == ei && j == ej) continue;\n        if (obstacle[i][j]) continue;\n        storableCells.push_back(vid(i, j));\n    }\n    const int M = (int)storableCells.size(); // = D^2-1-N\n\n    // Map cell -> container index k (0..M-1), or -1\n    vector<int> kOfCell(V, -1);\n    for (int k = 0; k < M; k++) kOfCell[storableCells[k]] = k;\n\n    // Precompute static distance from entrance ignoring containers (only obstacles)\n    const int INF = 1e9;\n    vector<int> dist(V, INF);\n    {\n        queue<int> q;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                if (obstacle[ni][nj]) continue;\n                int u = vid(ni, nj);\n                if (dist[u] > dist[v] + 1) {\n                    dist[u] = dist[v] + 1;\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    // Degree in obstacle-filtered grid\n    vector<int> deg(V, 0);\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) continue;\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            if (!inside(ni, nj)) continue;\n            if (obstacle[ni][nj]) continue;\n            c++;\n        }\n        deg[v] = c;\n    }\n\n    // Priority order for mapping small labels to \"easy early\" cells:\n    // close to entrance, higher degree (more accessible), then tie by coordinates.\n    vector<int> priority = storableCells;\n    sort(priority.begin(), priority.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    vector<int> rankv(V, -1);\n    for (int r = 0; r < M; r++) rankv[priority[r]] = r;\n\n    // Placement state\n    vector<char> occupied(V, 0);\n    vector<int> label_at(V, -1);\n\n    auto is_empty_placement = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;\n        return !occupied[v];\n    };\n\n    auto bfs_reachable_empty = [&](vector<char>& vis) -> int {\n        vis.assign(V, 0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n        int cnt = 1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_placement(u)) continue;\n                vis[u] = 1;\n                q.push(u);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    auto count_total_empty = [&]() -> int {\n        int total = 0;\n        for (int v = 0; v < V; v++) {\n            auto [i, j] = pos(v);\n            if (obstacle[i][j]) continue;\n            if (v == root) { total++; continue; }\n            if (!occupied[v]) total++;\n        }\n        return total;\n    };\n\n    auto placement_is_safe = [&](int cell) -> bool {\n        // cell is currently empty storable reachable; test that after occupying it,\n        // all remaining empty cells remain connected to entrance.\n        occupied[cell] = 1;\n        vector<char> vis;\n        int reach = bfs_reachable_empty(vis);\n        int total = count_total_empty();\n        occupied[cell] = 0;\n        return reach == total;\n    };\n\n    // ===== Placement phase (interactive) =====\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<char> vis;\n        bfs_reachable_empty(vis);\n\n        vector<int> candidates;\n        candidates.reserve(M);\n        for (int v : storableCells) {\n            if (occupied[v]) continue;\n            if (!vis[v]) continue; // must be reachable through empty squares\n            candidates.push_back(v);\n        }\n\n        // Score candidates: match label to rank, but must pass safety check.\n        // Try top L by heuristic first, then expand if needed.\n        struct Cand { int v; long long key; };\n        vector<Cand> order;\n        order.reserve(candidates.size());\n        for (int v : candidates) {\n            long long diff = (long long)rankv[v] - t;\n            long long key = diff * diff * 1000LL + dist[v] * 10LL - deg[v]; // heuristic only\n            order.push_back({v, key});\n        }\n        sort(order.begin(), order.end(), [&](const Cand& a, const Cand& b) {\n            if (a.key != b.key) return a.key < b.key;\n            return a.v < b.v;\n        });\n\n        int chosen = -1;\n        int L = min<int>(12, (int)order.size());\n        for (int i = 0; i < L; i++) {\n            int v = order[i].v;\n            if (placement_is_safe(v)) { chosen = v; break; }\n        }\n        if (chosen == -1) {\n            // fallback: brute search any safe candidate (guaranteed to exist)\n            for (auto &c : order) {\n                if (placement_is_safe(c.v)) { chosen = c.v; break; }\n            }\n        }\n        if (chosen == -1) {\n            // ultimate fallback (should never happen): pick first reachable\n            chosen = order[0].v;\n        }\n\n        occupied[chosen] = 1;\n        label_at[chosen] = t;\n        auto [pi, pj] = pos(chosen);\n        cout << pi << ' ' << pj << '\\n';\n        cout.flush();\n    }\n\n    // ===== Shipping phase =====\n    vector<int> labelOf(M);\n    for (int k = 0; k < M; k++) labelOf[k] = label_at[storableCells[k]];\n\n    // removedMask bit k => container removed (cell becomes empty)\n    unsigned __int128 removedMask = 0;\n\n    auto is_empty_ship = [&](int cell, unsigned __int128 mask) -> bool {\n        auto [i, j] = pos(cell);\n        if (obstacle[i][j]) return false;\n        if (cell == root) return true;\n        int k = kOfCell[cell];\n        if (k < 0) return false;\n        return ((mask >> k) & 1) != 0;\n    };\n\n    auto compute_boundary = [&](unsigned __int128 mask, vector<int>& boundary, int& reachEmpty) {\n        static array<char, 81> vis;\n        vis.fill(0);\n        array<int, 81> q;\n        int qh = 0, qt = 0;\n\n        vis[root] = 1;\n        q[qt++] = root;\n        while (qh < qt) {\n            int v = q[qh++];\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                if (vis[u]) continue;\n                if (!is_empty_ship(u, mask)) continue;\n                vis[u] = 1;\n                q[qt++] = u;\n            }\n        }\n        reachEmpty = qt;\n\n        static array<char, 80> seen; // M<=80\n        seen.fill(0);\n        boundary.clear();\n\n        for (int qi = 0; qi < qt; qi++) {\n            int v = q[qi];\n            auto [i, j] = pos(v);\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (!inside(ni, nj)) continue;\n                int u = vid(ni, nj);\n                int k = kOfCell[u];\n                if (k < 0) continue;\n                if (((mask >> k) & 1) != 0) continue; // already removed\n                if (!seen[k]) {\n                    seen[k] = 1;\n                    boundary.push_back(k);\n                }\n            }\n        }\n    };\n\n    auto min_boundary_labels_after = [&](unsigned __int128 mask, int& m1, int& m2, int& reachEmpty) {\n        vector<int> boundary;\n        compute_boundary(mask, boundary, reachEmpty);\n        m1 = M + 5; m2 = M + 5;\n        for (int k : boundary) {\n            int lab = labelOf[k];\n            if (lab < m1) { m2 = m1; m1 = lab; }\n            else if (lab < m2) { m2 = lab; }\n        }\n    };\n\n    for (int step = 0; step < M; step++) {\n        vector<int> boundary;\n        int reachEmpty = 0;\n        compute_boundary(removedMask, boundary, reachEmpty);\n\n        // boundary should always be non-empty until finished\n        if (boundary.empty()) {\n            // fallback (shouldn't happen): remove any remaining\n            for (int k = 0; k < M; k++) {\n                if (((removedMask >> k) & 1) == 0) { boundary.push_back(k); break; }\n            }\n        }\n\n        // Candidate set: few smallest labels + a few that may unlock (by distance/degree)\n        vector<int> byLabel = boundary;\n        sort(byLabel.begin(), byLabel.end(), [&](int a, int b) {\n            if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n            return a < b;\n        });\n        if ((int)byLabel.size() > 12) byLabel.resize(12);\n\n        vector<int> byUnlock = boundary;\n        sort(byUnlock.begin(), byUnlock.end(), [&](int a, int b) {\n            int ca = storableCells[a], cb = storableCells[b];\n            // prefer removing \"near entrance / high degree\" blockers\n            if (dist[ca] != dist[cb]) return dist[ca] < dist[cb];\n            if (deg[ca] != deg[cb]) return deg[ca] > deg[cb];\n            return a < b;\n        });\n        if ((int)byUnlock.size() > 6) byUnlock.resize(6);\n\n        vector<int> cand = byLabel;\n        cand.insert(cand.end(), byUnlock.begin(), byUnlock.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int bestK = cand[0];\n        long long bestScore = (1LL<<62);\n\n        for (int k : cand) {\n            unsigned __int128 newMask = removedMask | ((unsigned __int128)1 << k);\n\n            int m1, m2, reach2;\n            min_boundary_labels_after(newMask, m1, m2, reach2);\n\n            long long lab = labelOf[k];\n            // primary: keep sequence close to increasing => small label early\n            // secondary: unlock smaller labels soon (m1,m2), and grow reachable empty area\n            long long score = lab * 1000000LL + m1 * 5000LL + m2 * 500LL - reach2 * 5LL;\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestK = k;\n            }\n        }\n\n        removedMask |= (unsigned __int128)1 << bestK;\n        int cell = storableCells[bestK];\n        auto [qi, qj] = pos(cell);\n        cout << qi << ' ' << qj << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int DX[4] = {1, -1, 0, 0};\nstatic constexpr int DY[4] = {0, 0, 1, -1};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// splitmix64 for deterministic hashing\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> orig(n, vector<int>(n));\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> orig[i][j];\n\n    const int C = m + 1; // 0..m\n\n    auto inside = [&](int i, int j) { return (0 <= i && i < n && 0 <= j && j < n); };\n    auto is_boundary = [&](int i, int j) { return (i == 0 || i == n - 1 || j == 0 || j == n - 1); };\n    auto idx = [&](int i, int j) { return i * n + j; };\n\n    // Required adjacency existence\n    vector<vector<char>> req(C, vector<char>(C, 0));\n    vector<char> req0(C, 0);\n\n    // Non-zero adjacencies from original\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = orig[i][j];\n            if (i + 1 < n) {\n                int b = orig[i + 1][j];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n            if (j + 1 < n) {\n                int b = orig[i][j + 1];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n        }\n    }\n    // Outside adjacency: boundary touches 0\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) if (is_boundary(i, j)) {\n            int c = orig[i][j];\n            req[0][c] = req[c][0] = 1;\n            req0[c] = 1;\n        }\n    }\n\n    auto coastal = [&](int c) -> bool { return c > 0 && req0[c]; };\n\n    // Build adjacency list of colors (1..m), compute dist-to-coast on this graph\n    vector<vector<int>> adj(m + 1);\n    for (int u = 1; u <= m; u++) {\n        for (int v = 1; v <= m; v++) if (req[u][v]) adj[u].push_back(v);\n    }\n\n    const int INF = 1e9;\n    vector<int> dist(C, INF);\n    deque<int> q;\n    for (int c = 1; c <= m; c++) if (coastal(c)) { dist[c] = 0; q.push_back(c); }\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        for (int v : adj[u]) {\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push_back(v);\n            }\n        }\n    }\n\n    // Deterministic seed from input (avoid catastrophic variance)\n    uint64_t seed = 0;\n    seed ^= splitmix64((uint64_t)n * 1000003ULL + (uint64_t)m);\n    // sample a few cells\n    for (int i : {0, 1, 2, 7, 13, 23, 37, 49}) {\n        for (int j : {0, 3, 5, 11, 19, 29, 41, 49}) {\n            seed ^= splitmix64((uint64_t)(i + 1) * 1315423911ULL ^ (uint64_t)(j + 7) * 2654435761ULL ^ (uint64_t)orig[i][j]);\n        }\n    }\n    std::mt19937 rng((uint32_t)seed);\n\n    // Current grid\n    vector<vector<int>> g = orig;\n\n    // Sizes\n    vector<int> sz(C, 0);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) sz[g[i][j]]++;\n\n    // Edge counts ec[min][max]\n    vector<vector<int>> ec(C, vector<int>(C, 0));\n    auto addEdge = [&](int u, int v, int delta) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        ec[u][v] += delta;\n    };\n    auto getEdge = [&](int u, int v) -> int {\n        if (u == v) return 0;\n        if (u > v) swap(u, v);\n        return ec[u][v];\n    };\n\n    // init edge counts\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n        int a = g[i][j];\n        if (i + 1 < n) addEdge(a, g[i + 1][j], +1);\n        if (j + 1 < n) addEdge(a, g[i][j + 1], +1);\n        if (i == 0) addEdge(0, a, +1);\n        if (i == n - 1) addEdge(0, a, +1);\n        if (j == 0) addEdge(0, a, +1);\n        if (j == n - 1) addEdge(0, a, +1);\n    }\n\n    // Connectivity check for removing one cell of color c\n    vector<int> vis(n * n, 0);\n    int vis_stamp = 1;\n\n    auto connected_after_remove = [&](int i, int j, int c) -> bool {\n        int si = -1, sj = -1;\n        int same_deg = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == c) {\n                same_deg++;\n                if (si == -1) { si = ni; sj = nj; }\n            }\n        }\n        if (si == -1) return false;\n        if (same_deg <= 1) return true; // leaf removal safe\n\n        int target = sz[c] - 1;\n        vis_stamp++;\n        deque<pair<int,int>> qq;\n        qq.push_back({si, sj});\n        vis[idx(si, sj)] = vis_stamp;\n        int cnt = 1;\n        while (!qq.empty()) {\n            auto [x, y] = qq.front(); qq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!inside(nx, ny)) continue;\n                if (nx == i && ny == j) continue;\n                if (g[nx][ny] != c) continue;\n                int id = idx(nx, ny);\n                if (vis[id] == vis_stamp) continue;\n                vis[id] = vis_stamp;\n                qq.push_back({nx, ny});\n                cnt++;\n            }\n        }\n        return cnt == target;\n    };\n\n    auto adjacent_to_zero_or_outside = [&](int i, int j) -> bool {\n        if (is_boundary(i, j)) return true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == 0) return true;\n        }\n        return false;\n    };\n\n    // Necessary local compatibility for recolor to b\n    auto locally_compatible = [&](int i, int j, int b) -> bool {\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d == b) continue;\n            if (!req[b][d]) return false;\n        }\n        return true;\n    };\n\n    // Core legal move: recolor old -> newc (newc can be 0)\n    auto try_apply = [&](int i, int j, int newc) -> bool {\n        int old = g[i][j];\n        if (old == 0 || old == newc) return false;\n        if (sz[old] <= 1) return false;\n\n        if (newc == 0) {\n            if (!adjacent_to_zero_or_outside(i, j)) return false;\n        } else {\n            bool touch = false;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj) && g[ni][nj] == newc) { touch = true; break; }\n            }\n            if (!touch) return false;\n        }\n\n        if (!connected_after_remove(i, j, old)) return false;\n\n        int keys[16], vals[16], ksz = 0;\n        auto addDelta = [&](int u, int v, int delta) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            int key = u * C + v;\n            for (int t = 0; t < ksz; t++) if (keys[t] == key) { vals[t] += delta; return; }\n            keys[ksz] = key;\n            vals[ksz] = delta;\n            ksz++;\n        };\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addDelta(old, d, -1);\n            if (newc != d) addDelta(newc, d, +1);\n        }\n\n        for (int t = 0; t < ksz; t++) {\n            int key = keys[t];\n            int u = key / C;\n            int v = key % C;\n            int cur = getEdge(u, v);\n            int nxt = cur + vals[t];\n            if (nxt < 0) return false;\n            if (req[u][v]) { if (nxt == 0) return false; }\n            else { if (nxt != 0) return false; }\n        }\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addEdge(old, d, -1);\n            if (newc != d) addEdge(newc, d, +1);\n        }\n\n        g[i][j] = newc;\n        sz[old]--;\n        if (newc > 0) sz[newc]++;\n\n        return true;\n    };\n\n    // Precheck for deletion c->0: any neighbor d!=c that becomes adjacent to 0 must be coastal\n    auto delete_precheck = [&](int i, int j) -> bool {\n        int c = g[i][j];\n        if (c <= 0 || !coastal(c)) return false;\n        if (!adjacent_to_zero_or_outside(i, j)) return false;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d > 0 && d != c && !coastal(d)) return false;\n        }\n        return true;\n    };\n\n    Timer timer;\n    const double TL = 1.90;\n    const double PHASE1 = 1.25; // IMPORTANT: recolor-only phase (stability)\n\n    // Candidate pool with duplicates (high-throughput exploration)\n    vector<int> cand;\n    cand.reserve(n * n * 10);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cand.push_back(idx(i, j));\n\n    auto push_around = [&](int i, int j) {\n        for (int di = -1; di <= 1; di++) for (int dj = -1; dj <= 1; dj++) {\n            int x = i + di, y = j + dj;\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n        for (int k = 0; k < 4; k++) {\n            int x = i + DX[k], y = j + DY[k];\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n    };\n\n    auto refill = [&]() {\n        // keep pool populated but bounded\n        if ((int)cand.size() < 8000) {\n            for (int t = 0; t < 8000; t++) cand.push_back((int)(rng() % (n * n)));\n        }\n        if ((int)cand.size() > 300000) {\n            // downsample to avoid memory/time blowups\n            vector<int> tmp;\n            tmp.reserve(120000);\n            for (int t = 0; t < 120000; t++) tmp.push_back(cand[rng() % cand.size()]);\n            cand.swap(tmp);\n        }\n    };\n\n    // Main loop\n    while (timer.elapsed() < TL) {\n        refill();\n        int pos = (int)(rng() % cand.size());\n        int id = cand[pos];\n        cand[pos] = cand.back();\n        cand.pop_back();\n\n        int i = id / n, j = id % n;\n        int old = g[i][j];\n        if (old == 0) continue;\n\n        bool allowDelete = (timer.elapsed() >= PHASE1);\n\n        // Phase2: try delete first\n        if (allowDelete && delete_precheck(i, j)) {\n            if (try_apply(i, j, 0)) {\n                push_around(i, j);\n                continue;\n            }\n        }\n\n        // Recolor: choose neighbor with smaller dist (or equal dist rarely)\n        int neigh[4]; int ns = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (!inside(ni, nj)) continue;\n            int b = g[ni][nj];\n            if (b > 0 && b != old) neigh[ns++] = b;\n        }\n        if (ns == 0) continue;\n        sort(neigh, neigh + ns);\n        ns = (int)(unique(neigh, neigh + ns) - neigh);\n\n        // Sort by dist then prefer coastal to help later deletions\n        vector<int> opts(neigh, neigh + ns);\n        sort(opts.begin(), opts.end(), [&](int a, int b) {\n            if (dist[a] != dist[b]) return dist[a] < dist[b];\n            return (int)coastal(a) > (int)coastal(b);\n        });\n\n        int dOld = dist[old];\n        for (int b : opts) {\n            int dNew = dist[b];\n            if (dNew > dOld) continue;\n            if (dNew == dOld) {\n                // exploration probability (a bit higher in phase2)\n                int P = allowDelete ? 60 : 180;\n                if ((int)(rng() % P) != 0) continue;\n            }\n            if (!locally_compatible(i, j, b)) continue;\n            if (try_apply(i, j, b)) {\n                push_around(i, j);\n                break;\n            }\n        }\n    }\n\n    // Final greedy deletion flood: seed from boundary AND current 0-frontier\n    deque<int> dq;\n    vector<char> inq(n * n, 0);\n    auto push_del = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        int id = idx(x, y);\n        if (!inq[id]) { inq[id] = 1; dq.push_back(id); }\n    };\n\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n        if (is_boundary(i, j)) push_del(i, j);\n        if (g[i][j] == 0) {\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj)) push_del(ni, nj);\n            }\n        }\n    }\n\n    while (!dq.empty() && timer.elapsed() < TL) {\n        int id = dq.front(); dq.pop_front();\n        inq[id] = 0;\n        int i = id / n, j = id % n;\n        if (!delete_precheck(i, j)) continue;\n        if (try_apply(i, j, 0)) {\n            push_del(i, j);\n            for (int k = 0; k < 4; k++) push_del(i + DX[k], j + DY[k]);\n        }\n    }\n\n    // Safety verify (fallback to orig if anything wrong)\n    auto verify = [&]() -> bool {\n        vector<int> cnt(C, 0);\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cnt[g[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cnt[c] == 0) return false;\n\n        // connectivity for colors 1..m\n        vector<int> v(n * n, 0);\n        int st = 1;\n        for (int c = 1; c <= m; c++) {\n            int si = -1, sj = -1;\n            for (int i = 0; i < n && si == -1; i++)\n                for (int j = 0; j < n; j++)\n                    if (g[i][j] == c) { si = i; sj = j; break; }\n            st++;\n            deque<pair<int,int>> qq;\n            qq.push_back({si, sj});\n            v[idx(si, sj)] = st;\n            int got = 1;\n            while (!qq.empty()) {\n                auto [x, y] = qq.front(); qq.pop_front();\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + DX[k], ny = y + DY[k];\n                    if (!inside(nx, ny)) continue;\n                    if (g[nx][ny] != c) continue;\n                    int id2 = idx(nx, ny);\n                    if (v[id2] == st) continue;\n                    v[id2] = st;\n                    qq.push_back({nx, ny});\n                    got++;\n                }\n            }\n            if (got != cnt[c]) return false;\n        }\n\n        // 0 connected to outside (padded BFS)\n        int N = n + 2;\n        auto at = [&](int x, int y) -> int {\n            if (x == 0 || y == 0 || x == N - 1 || y == N - 1) return 0;\n            return g[x - 1][y - 1];\n        };\n        vector<char> vz(N * N, 0);\n        deque<pair<int,int>> q0;\n        q0.push_back({0, 0});\n        vz[0] = 1;\n        while (!q0.empty()) {\n            auto [x, y] = q0.front(); q0.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < N && 0 <= ny && ny < N)) continue;\n                int nid = nx * N + ny;\n                if (vz[nid]) continue;\n                if (at(nx, ny) != 0) continue;\n                vz[nid] = 1;\n                q0.push_back({nx, ny});\n            }\n        }\n        for (int x = 1; x <= n; x++)\n            for (int y = 1; y <= n; y++)\n                if (g[x - 1][y - 1] == 0 && !vz[x * N + y]) return false;\n\n        // adjacency graph equals req\n        vector<vector<char>> outAdj(C, vector<char>(C, 0));\n        auto mark = [&](int u, int v) {\n            if (u == v) return;\n            outAdj[u][v] = outAdj[v][u] = 1;\n        };\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n            int a = g[i][j];\n            if (i + 1 < n) mark(a, g[i + 1][j]);\n            if (j + 1 < n) mark(a, g[i][j + 1]);\n            if (i == 0) mark(0, a);\n            if (i == n - 1) mark(0, a);\n            if (j == 0) mark(0, a);\n            if (j == n - 1) mark(0, a);\n        }\n        for (int u = 0; u <= m; u++)\n            for (int v = u + 1; v <= m; v++)\n                if (outAdj[u][v] != req[u][v]) return false;\n\n        return true;\n    };\n\n    if (!verify()) g = orig;\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (j) cout << ' ';\n            cout << g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    using ull = unsigned long long;\n    ull x;\n    explicit XorShift(ull seed = 88172645463325252ULL) : x(seed) {}\n    ull nextUll() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextUll() % (ull)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int cmpLimit = 0; // after this, cmpItem becomes deterministic (no more queries)\n\n    vector<vector<int>> bins;\n    vector<int> ans;\n\n    // itemCmp[a][b] for a<b: 2 unknown, else -1/0/1 meaning wa ? wb\n    vector<vector<int8_t>> itemCmp;\n\n    XorShift rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    char querySets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) return '=';\n        cout << (int)L.size() << \" \" << (int)R.size();\n        for (int x : L) cout << \" \" << x;\n        for (int x : R) cout << \" \" << x;\n        cout << \"\\n\";\n        cout.flush();\n        string s;\n        cin >> s;\n        used++;\n        return s[0];\n    }\n\n    int cmpItem(int i, int j) {\n        if (i == j) return 0;\n        // If out of budget for item comparisons, fall back to deterministic ordering.\n        if (used >= Q || used >= cmpLimit) return (i < j ? -1 : +1);\n\n        int a = min(i, j), b = max(i, j);\n        int8_t &v = itemCmp[a][b];\n        if (v != 2) {\n            int res = (int)v;\n            return (i == a ? res : -res);\n        }\n        char r = querySets(vector<int>{i}, vector<int>{j});\n        int res = (r == '<' ? -1 : (r == '>' ? +1 : 0));\n        int store = (i == a ? res : -res);\n        v = (int8_t)store;\n        return res;\n    }\n\n    static int ceil_log2(int n) {\n        int k = 0, p = 1;\n        while (p < n) { p <<= 1; k++; }\n        return k;\n    }\n    static long long clamp_ll(long long x, long long lo, long long hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    // Build max-tournament among items, record beaten lists.\n    int buildTournament(const vector<int>& items, vector<vector<int>>& beaten) {\n        vector<int> cur = items;\n        while ((int)cur.size() > 1 && used < cmpLimit) {\n            vector<int> nxt;\n            nxt.reserve((cur.size() + 1) / 2);\n            for (int i = 0; i < (int)cur.size(); i += 2) {\n                if (i + 1 == (int)cur.size()) {\n                    nxt.push_back(cur[i]);\n                } else {\n                    int a = cur[i], b = cur[i + 1];\n                    int c = cmpItem(a, b);\n                    int win = (c >= 0 ? a : b);\n                    int lose = (c >= 0 ? b : a);\n                    beaten[win].push_back(lose);\n                    nxt.push_back(win);\n                }\n            }\n            cur.swap(nxt);\n        }\n        return cur[0];\n    }\n\n    // Explicit-comparator heap (avoids UB)\n    struct MaxHeap {\n        Solver* s;\n        vector<int> h;\n        explicit MaxHeap(Solver* ss) : s(ss) {}\n        bool higher(int a, int b) { // true if a heavier than b\n            int c = s->cmpItem(a, b);\n            if (c == 0) return a > b;\n            return c > 0;\n        }\n        void push(int x) {\n            h.push_back(x);\n            int i = (int)h.size() - 1;\n            while (i > 0) {\n                int p = (i - 1) / 2;\n                if (!higher(h[i], h[p])) break;\n                swap(h[i], h[p]);\n                i = p;\n            }\n        }\n        int pop() {\n            int ret = h[0];\n            h[0] = h.back();\n            h.pop_back();\n            int n = (int)h.size();\n            int i = 0;\n            while (true) {\n                int l = 2*i + 1, r = 2*i + 2;\n                if (l >= n) break;\n                int best = l;\n                if (r < n && higher(h[r], h[l])) best = r;\n                if (!higher(h[best], h[i])) break;\n                swap(h[best], h[i]);\n                i = best;\n            }\n            return ret;\n        }\n        bool empty() const { return h.empty(); }\n    };\n\n    // Pivot bucketing for remaining items (heavy->light), bounded by cmpLimit through cmpItem fallback.\n    vector<int> approxOrderHeavyByPivots(vector<int> vec) {\n        int n = (int)vec.size();\n        if (n <= 1) return vec;\n\n        for (int i = n - 1; i > 0; i--) swap(vec[i], vec[rng.nextInt(0, i)]);\n\n        auto costForP = [&](int P) -> int {\n            if (P <= 1) return 0;\n            int lg = ceil_log2(P);\n            return P * lg + (n - P) * lg;\n        };\n\n        int remaining = max(0, cmpLimit - used);\n        int P = 2;\n        for (int cand : {32, 16, 8, 4, 2}) {\n            if (cand <= n && costForP(cand) <= remaining) { P = cand; break; }\n        }\n        if (P > n) P = n;\n        if (P < 2) return vec;\n\n        vector<int> piv(vec.begin(), vec.begin() + P);\n        vector<int> rest(vec.begin() + P, vec.end());\n\n        // insertion sort pivots ascending\n        for (int i = 1; i < P; i++) {\n            int x = piv[i];\n            int j = i - 1;\n            while (j >= 0) {\n                int c = cmpItem(piv[j], x);\n                if (c <= 0) break;\n                piv[j + 1] = piv[j];\n                j--;\n            }\n            piv[j + 1] = x;\n        }\n\n        vector<vector<int>> bucket(P + 1);\n        for (int x : rest) {\n            int lo = 0, hi = P;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                int c = cmpItem(x, piv[mid]);\n                if (c < 0) hi = mid;\n                else lo = mid + 1;\n            }\n            bucket[lo].push_back(x);\n        }\n\n        for (auto &b : bucket) {\n            for (int i = (int)b.size() - 1; i > 0; i--) swap(b[i], b[rng.nextInt(0, i)]);\n        }\n\n        vector<int> order;\n        order.reserve(n);\n        for (int j = P; j >= 1; j--) {\n            for (int x : bucket[j]) order.push_back(x);\n            order.push_back(piv[j - 1]);\n        }\n        for (int x : bucket[0]) order.push_back(x);\n\n        // ensure permutation of vec\n        vector<char> seen(N, 0);\n        vector<int> fixed;\n        fixed.reserve(n);\n        for (int x : order) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n        for (int x : vec) if (!seen[x]) fixed.push_back(x);\n        return fixed;\n    }\n\n    void moveItem(int item, int from, int to) {\n        auto &vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); i++) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        ans[item] = to;\n    }\n\n    int trueLightestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '>') best = i;\n        }\n        return best;\n    }\n    int trueHeaviestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '<') best = i;\n        }\n        return best;\n    }\n\n    static int argminSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] < s[idx]) idx = i;\n        return idx;\n    }\n    static int argmaxSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] > s[idx]) idx = i;\n        return idx;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        unsigned long long seed = 1234567ULL;\n        seed ^= (unsigned long long)N * 1000003ULL;\n        seed ^= (unsigned long long)D * 10007ULL;\n        seed ^= (unsigned long long)Q * 97ULL;\n        rng = XorShift(seed);\n\n        used = 0;\n        bins.assign(D, {});\n        ans.assign(N, 0);\n        itemCmp.assign(N, vector<int8_t>(N, 2));\n\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        for (int i = N - 1; i > 0; i--) swap(items[i], items[rng.nextInt(0, i)]);\n\n        // ---- Budget split: keep enough for refinement, but not destroy ordering quality ----\n        int reserveImprove = max(2 * (D - 1) + 30, Q / 4);\n        reserveImprove = min(reserveImprove, 900);\n        int budgetOrder = Q - reserveImprove;\n\n        // Need at least N-1 queries to build a tournament; if not, just use all.\n        budgetOrder = max(budgetOrder, N - 1);\n        budgetOrder = min(budgetOrder, Q);\n        reserveImprove = Q - budgetOrder;\n\n        cmpLimit = budgetOrder;\n\n        // ---- Ordering: tournament top extraction + pivots for rest ----\n        vector<vector<int>> beaten(N);\n        int maxItem = buildTournament(items, beaten);\n\n        // Extract top-K (more for larger Q)\n        int Ktarget = min(N, max(2 * D, (Q >= 8 * N ? 4 * D : 2 * D)));\n        vector<int> heavyPrefix;\n        heavyPrefix.reserve(Ktarget);\n\n        vector<char> picked(N, 0);\n        MaxHeap heap(this);\n        heap.push(maxItem);\n        while (!heap.empty() && (int)heavyPrefix.size() < Ktarget && used < cmpLimit) {\n            int x = heap.pop();\n            if (picked[x]) continue;\n            picked[x] = 1;\n            heavyPrefix.push_back(x);\n            for (int y : beaten[x]) if (!picked[y]) heap.push(y);\n        }\n\n        vector<int> rest;\n        rest.reserve(N);\n        for (int x : items) if (!picked[x]) rest.push_back(x);\n\n        vector<int> orderHeavyToLight = heavyPrefix;\n        if (!rest.empty()) {\n            vector<int> approxRest = approxOrderHeavyByPivots(rest);\n            orderHeavyToLight.insert(orderHeavyToLight.end(), approxRest.begin(), approxRest.end());\n        }\n\n        // ensure permutation\n        {\n            vector<char> seen(N, 0);\n            vector<int> fixed;\n            fixed.reserve(N);\n            for (int x : orderHeavyToLight) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n            for (int x : items) if (!seen[x]) fixed.push_back(x);\n            orderHeavyToLight.swap(fixed);\n        }\n\n        // ---- Estimated weights from ranks (compressed heavy tail) ----\n        vector<int> orderLightToHeavy(orderHeavyToLight.rbegin(), orderHeavyToLight.rend());\n\n        const long double lambda = 1e-5L;\n        long long M = (long long)100000 * N / D;\n\n        // compress: w = (-ln(1-p)/lambda)^alpha\n        const long double alpha = 0.80L;\n\n        vector<long long> rankW(N, 1);\n        for (int r = 0; r < N; r++) {\n            long double p = (r + 0.5L) / (long double)N;\n            long double base = -logl(1.0L - p) / lambda;\n            long double v = powl(base, alpha);\n            long long w = (long long) llround((double)v);\n            w = clamp_ll(w, 1, M);\n            rankW[r] = w;\n        }\n        // enforce monotone and cap growth except for top few ranks\n        for (int r = 1; r < N; r++) rankW[r] = max(rankW[r], rankW[r - 1]);\n        int protectTop = min(N, max(10, 2 * D)); // keep steepness only at very top\n        for (int r = 1; r < N - protectTop; r++) {\n            long long cap = rankW[r - 1] + max(10LL, rankW[r - 1] / 4); // +25%\n            if (rankW[r] > cap) rankW[r] = cap;\n        }\n        vector<long long> estW(N, 1);\n        for (int r = 0; r < N; r++) estW[orderLightToHeavy[r]] = rankW[r];\n\n        // ---- Initial partition: LPT on estW ----\n        bins.assign(D, {});\n        vector<long long> sumEst(D, 0);\n        ans.assign(N, 0);\n\n        // Seed with top D items\n        for (int b = 0; b < D; b++) {\n            int it = orderHeavyToLight[b];\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n        }\n\n        struct Node { long long s; int b; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.s > b.s; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        for (int b = 0; b < D; b++) pq.push({sumEst[b], b});\n\n        for (int idx = D; idx < N; idx++) {\n            int it = orderHeavyToLight[idx];\n            auto cur = pq.top(); pq.pop();\n            int b = cur.b;\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n            pq.push({sumEst[b], b});\n        }\n\n        // ---- Offline improvement on estW (moves + small swaps) ----\n        for (int iter = 0; iter < 8000; iter++) {\n            int H = argmaxSum(sumEst);\n            int L = argminSum(sumEst);\n            long long diff = sumEst[H] - sumEst[L];\n            if (diff <= 0) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // best move\n            int bestX = -1;\n            long long bestAbs = llabs(diff);\n            for (int x : bins[H]) {\n                long long nd = (sumEst[H] - estW[x]) - (sumEst[L] + estW[x]);\n                long long absd = llabs(nd);\n                if (absd < bestAbs) { bestAbs = absd; bestX = x; }\n            }\n            if (bestX != -1) {\n                sumEst[H] -= estW[bestX];\n                sumEst[L] += estW[bestX];\n                moveItem(bestX, H, L);\n                continue;\n            }\n\n            // small swap candidates\n            vector<int> candH = bins[H], candL = bins[L];\n            sort(candH.begin(), candH.end(), [&](int a, int b){ return estW[a] > estW[b]; });\n            sort(candL.begin(), candL.end(), [&](int a, int b){ return estW[a] < estW[b]; });\n            int takeH = min(3, (int)candH.size());\n            int takeL = min(3, (int)candL.size());\n\n            int bestA = -1, bestB = -1;\n            bestAbs = llabs(diff);\n            for (int i = 0; i < takeH; i++) for (int j = 0; j < takeL; j++) {\n                int a = candH[i], b = candL[j];\n                long long nd = (sumEst[H] - estW[a] + estW[b]) - (sumEst[L] - estW[b] + estW[a]);\n                long long absd = llabs(nd);\n                if (absd < bestAbs) { bestAbs = absd; bestA = a; bestB = b; }\n            }\n            if (bestA == -1) break;\n\n            sumEst[H] = sumEst[H] - estW[bestA] + estW[bestB];\n            sumEst[L] = sumEst[L] - estW[bestB] + estW[bestA];\n            for (int &x : bins[H]) if (x == bestA) { x = bestB; break; }\n            for (int &x : bins[L]) if (x == bestB) { x = bestA; break; }\n            ans[bestA] = L;\n            ans[bestB] = H;\n        }\n\n        // ---- Interactive refinement (use remaining queries only here) ----\n        cmpLimit = Q; // allow cmpItem again if we need it (rare)\n\n        while (used < Q) {\n            int remQ = Q - used;\n            if (remQ < 2 * (D - 1) + 2) break; // need extremes + at least 1 probe\n\n            int L = trueLightestBin();\n            if (used >= Q) break;\n            int H = trueHeaviestBin();\n            if (used >= Q) break;\n            if (L == H) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // Try to move an item x from H to L.\n            // Use binary-search-like probes on items sorted by estW.\n            vector<int> cand = bins[H];\n            sort(cand.begin(), cand.end(), [&](int a, int b){ return estW[a] < estW[b]; }); // light..heavy\n\n            int lo = 0, hi = (int)cand.size() - 1;\n            int bestEq = -1;\n            int bestStill = -1;   // r='>'  (newH > newL) => x too light\n            int bestOver = -1;    // r='<'  (newH < newL) => x too heavy\n            long double bestPredAbs = 1e100L;\n            int bestByPred = -1;\n\n            int probes = min(6, Q - used);\n            for (int step = 0; step < probes && lo <= hi && used < Q; step++) {\n                int mid = (lo + hi) >> 1;\n                int x = cand[mid];\n\n                // Build A = H \\ {x}, B = L U {x}\n                vector<int> A;\n                A.reserve(bins[H].size() - 1);\n                for (int y : bins[H]) if (y != x) A.push_back(y);\n                if (A.empty()) break;\n                vector<int> B = bins[L];\n                B.push_back(x);\n\n                char r = querySets(A, B);\n\n                long long pred = (sumEst[H] - estW[x]) - (sumEst[L] + estW[x]);\n                long double ap = fabsl((long double)pred);\n                if (ap < bestPredAbs) { bestPredAbs = ap; bestByPred = x; }\n\n                if (r == '=') { bestEq = x; break; }\n                if (r == '>') { bestStill = x; lo = mid + 1; } // need heavier x\n                else { bestOver = x; hi = mid - 1; }           // need lighter x\n            }\n\n            int chosen = -1;\n            if (bestEq != -1) chosen = bestEq;\n            else if (bestByPred != -1) chosen = bestByPred;\n            else if (bestStill != -1) chosen = bestStill;\n            else chosen = bestOver;\n\n            if (chosen == -1) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // Apply move (update estimated sums)\n            sumEst[H] -= estW[chosen];\n            sumEst[L] += estW[chosen];\n            moveItem(chosen, H, L);\n        }\n\n        // Dummy queries to reach exactly Q\n        while (used < Q) querySets(vector<int>{0}, vector<int>{1});\n\n        // Final clamp\n        for (int i = 0; i < N; i++) if (ans[i] < 0 || ans[i] >= D) ans[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << \"\\n\";\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 200;\nstatic constexpr int M = 10;\nstatic constexpr int INF = INT_MAX;\n\nstruct Weights {\n    double wHeight = 0.06;\n    double wMinUrg = 230.0;\n    double wTopUrg = 85.0;\n    double wMinAtTopExtra = 260.0;\n\n    double badTopBase = 4200.0;\n    double badTopPerCnt = 220.0;     // per moved item that is > dest.top\n    double badMinBase = 2600.0;\n    double badMinPerCnt = 260.0;     // per moved item that is > dest.min (scaled by urgency)\n\n    double emptyReserve = 35.0;\n\n    int lookahead = 14;      // simulation removals\n    int destCand = 6;        // destinations tried per action\n    int cmax = 6;            // max chunk size (top peeling) considered\n};\n\nstruct Result {\n    long long energy = (1LL<<60);\n    vector<pair<int,int>> ops;\n};\n\nstatic inline uint64_t xorshift64(uint64_t &x) {\n    x ^= x << 7;\n    x ^= x >> 9;\n    return x;\n}\n\nstruct State {\n    array<array<int, N>, M> a{};\n    array<int, M> sz{};\n\n    array<int, N + 1> posS{};\n    array<int, N + 1> posI{};\n\n    array<int, M> top{};\n    array<int, M> mn{};\n    array<int, M> posMinFromTop{};\n\n    void recalc(int i) {\n        int h = sz[i];\n        if (h == 0) {\n            top[i] = INF;\n            mn[i] = INF;\n            posMinFromTop[i] = 0;\n            return;\n        }\n        top[i] = a[i][h - 1];\n        int best = INF, bestIdx = 0;\n        for (int j = 0; j < h; j++) {\n            int v = a[i][j];\n            if (v < best) {\n                best = v;\n                bestIdx = j;\n            }\n        }\n        mn[i] = best;\n        posMinFromTop[i] = (h - 1) - bestIdx;\n    }\n\n    void initFromInput(const vector<vector<int>> &init) {\n        for (int i = 0; i < M; i++) {\n            sz[i] = (int)init[i].size();\n            for (int j = 0; j < sz[i]; j++) {\n                a[i][j] = init[i][j];\n                posS[a[i][j]] = i;\n                posI[a[i][j]] = j;\n            }\n        }\n        for (int i = 0; i < M; i++) recalc(i);\n    }\n\n    inline pair<int,int> locate(int v) const {\n        return {posS[v], posI[v]};\n    }\n    inline bool isOnTop(int v) const {\n        auto [s, idx] = locate(v);\n        return s >= 0 && idx == sz[s] - 1;\n    }\n\n    inline void popTop(int s) {\n        int v = a[s][sz[s] - 1];\n        sz[s]--;\n        posS[v] = -1;\n        posI[v] = -1;\n        recalc(s);\n    }\n\n    inline void moveSuffix(int s, int start, int d) {\n        int k = sz[s] - start;\n        int base = sz[d];\n        for (int i = 0; i < k; i++) {\n            int x = a[s][start + i];\n            a[d][base + i] = x;\n            posS[x] = d;\n            posI[x] = base + i;\n        }\n        sz[d] += k;\n        sz[s] = start;\n        recalc(s);\n        recalc(d);\n    }\n};\n\nstruct MovePlan {\n    // operation 1: move suffix starting at 'start' from stack s to stack d\n    int s = -1;\n    int d = -1;\n    int start = -1;\n    int len = 0;\n    int v = -1;\n    long long eval = (1LL<<62);\n};\n\nstruct Solver {\n    State init;\n\n    explicit Solver(const vector<vector<int>> &st0) {\n        init.initFromInput(st0);\n    }\n\n    // Collect moved values into buf[0..len)\n    static inline int collectMoved(const State &st, int s, int start, int *buf) {\n        int len = st.sz[s] - start;\n        for (int i = 0; i < len; i++) buf[i] = st.a[s][start + i];\n        return len;\n    }\n\n    static inline int maxOfBuf(const int *buf, int len) {\n        int mx = 0;\n        for (int i = 0; i < len; i++) mx = max(mx, buf[i]);\n        return mx;\n    }\n\n    static inline double destPenaltyWithBuf(\n        const State &st,\n        int t,\n        int s, int d,\n        const int *buf, int len,\n        int bufMax,\n        const Weights &w\n    ) {\n        if (d == s) return 1e100;\n\n        int h = st.sz[d];\n        if (h == 0) {\n            // safe but slightly reserved\n            return w.emptyReserve + w.wHeight * double(len);\n        }\n\n        int top = st.top[d];\n        int mn = st.mn[d];\n        int posMin = st.posMinFromTop[d];\n\n        double deltaMin = double(mn - t);\n        double deltaTop = double(top - t);\n        if (deltaMin < 1.0) deltaMin = 1.0;\n        if (deltaTop < 1.0) deltaTop = 1.0;\n\n        // counts of \"blocking\" items after placing buf on destination\n        int cntAboveTop = 0;\n        int cntAboveMin = 0;\n        if (top != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > top) cntAboveTop++;\n        }\n        if (mn != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > mn) cntAboveMin++;\n        }\n\n        double p = 0.0;\n        p += w.wHeight * double(h + len);\n        p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n        p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n\n        if (posMin == 0) {\n            p += w.wMinAtTopExtra * double(len + 1) / (deltaMin + 1.0);\n        }\n\n        // Strong penalties when we bury a smaller top/min under larger moved values\n        if (cntAboveTop > 0) {\n            // also factor severity by how much bigger the move max is than top (mildly)\n            p += w.badTopBase + w.badTopPerCnt * cntAboveTop + 2.0 * max(0, bufMax - top);\n        }\n        if (cntAboveMin > 0) {\n            p += (w.badMinBase + w.badMinPerCnt * cntAboveMin) / (deltaMin + 1.0);\n        }\n\n        return p;\n    }\n\n    static int chooseDestBase(const State &st, int t, int s, int start, const Weights &w) {\n        int len = st.sz[s] - start;\n        int mx = 0;\n        for (int i = start; i < st.sz[s]; i++) mx = max(mx, st.a[s][i]);\n\n        // safe stack: mn > mx\n        int bestSafe = -1;\n        int bestH = INF;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > mx) {\n                int h = st.sz[d];\n                if (h < bestH) {\n                    bestH = h;\n                    bestSafe = d;\n                }\n            }\n        }\n        if (bestSafe != -1) return bestSafe;\n\n        // otherwise minimize a cheap proxy\n        double bestP = 1e100;\n        int bestD = (s + 1) % M;\n        for (int d = 0; d < M; d++) if (d != s) {\n            int h = st.sz[d];\n            int top = st.top[d];\n            int mn = st.mn[d];\n            double deltaMin = max(1.0, double(mn - t));\n            double deltaTop = max(1.0, double(top - t));\n            double p = 0.0;\n            if (h == 0) p += w.emptyReserve;\n            p += w.wHeight * double(h + len);\n            p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n            p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n            if (top < mx) p += w.badTopBase;\n            if (mn < mx) p += w.badMinBase / (deltaMin + 1.0);\n            if (p < bestP) { bestP = p; bestD = d; }\n        }\n        return bestD;\n    }\n\n    static long long simulateEnergy(State st, int tStart, int maxRemovals, const Weights &w) {\n        long long e = 0;\n        int t = tStart;\n        int removed = 0;\n\n        while (t <= N && removed < maxRemovals) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                st.popTop(s);\n                t++;\n                removed++;\n            } else {\n                int start = idx + 1;\n                int len = st.sz[s] - start;\n                int d = chooseDestBase(st, t, s, start, w);\n                st.moveSuffix(s, start, d);\n                e += (long long)len + 1;\n            }\n        }\n        return e;\n    }\n\n    // Decide the next move when t is not on top:\n    // either move whole above-t pile, or peel top c boxes, using 1-step search + lookahead.\n    static MovePlan decideMove(State const &st, int t, const Weights &w, uint64_t &rng, int opsLeft) {\n        auto [s, idx] = st.locate(t);\n        int kTotal = st.sz[s] - idx - 1;\n\n        MovePlan best;\n        best.eval = (1LL<<62);\n\n        // If operation budget is tight, avoid peeling.\n        bool tight = (opsLeft < 250);\n\n        // Precompute whole-pile info\n        int bufAll[N];\n        int startAll = idx + 1;\n        int lenAll = collectMoved(st, s, startAll, bufAll);\n        int maxAll = maxOfBuf(bufAll, lenAll);\n\n        bool existsSafeForAll = false;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > maxAll) { existsSafeForAll = true; break; }\n        }\n\n        // Gate: peeling search mainly when whole move has no safe destination or pile is small\n        bool doPeelSearch = (!tight) && (!existsSafeForAll || kTotal <= 10);\n\n        // Candidate actions: always include whole move, plus top-c peel moves if enabled\n        vector<pair<int,int>> actions; // (start, len)\n        actions.push_back({startAll, lenAll});\n        if (doPeelSearch) {\n            int cmax = min(w.cmax, kTotal);\n            for (int c = 1; c <= cmax; c++) {\n                int start = st.sz[s] - c;\n                if (start <= idx) continue; // must not include t\n                actions.push_back({start, c});\n            }\n        }\n\n        // Evaluate each action by trying best few destinations (ranked by penalty) and simulating\n        for (auto [start, len] : actions) {\n            int buf[N];\n            int got = collectMoved(st, s, start, buf);\n            (void)got;\n            int bufMax = maxOfBuf(buf, len);\n\n            // Rank destinations\n            vector<pair<double,int>> ranked;\n            ranked.reserve(M - 1);\n            for (int d = 0; d < M; d++) if (d != s) {\n                double p = destPenaltyWithBuf(st, t, s, d, buf, len, bufMax, w);\n                // tiny noise to diversify between trials\n                p += double(int(xorshift64(rng) % 1000)) * 1e-9;\n                ranked.push_back({p, d});\n            }\n            sort(ranked.begin(), ranked.end());\n\n            int D = min(w.destCand, (int)ranked.size());\n            for (int i = 0; i < D; i++) {\n                int d = ranked[i].second;\n                State st2 = st;\n                st2.moveSuffix(s, start, d);\n                long long score = (long long)len + 1;\n                score += simulateEnergy(st2, t, w.lookahead, w);\n\n                // mild bias: avoid excessive peeling unless it helps\n                if (len <= w.cmax && len != lenAll) score += 1; // tiny +1 (not energy), just tie-break\n\n                if (score < best.eval) {\n                    best.eval = score;\n                    best.s = s;\n                    best.d = d;\n                    best.start = start;\n                    best.len = len;\n                    best.v = st.a[s][start];\n                }\n            }\n        }\n\n        // Fallback (shouldn't happen)\n        if (best.s < 0) {\n            best.s = s;\n            best.start = startAll;\n            best.len = lenAll;\n            best.v = st.a[s][startAll];\n            best.d = (s + 1) % M;\n            best.eval = (long long)lenAll + 1;\n        }\n        return best;\n    }\n\n    Result run(const Weights &w, uint64_t seed) {\n        uint64_t rng = seed;\n        State st = init;\n\n        vector<pair<int,int>> ops;\n        ops.reserve(2500);\n\n        long long energy = 0;\n        int t = 1;\n\n        while (t <= N) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                ops.push_back({t, 0});\n                st.popTop(s);\n                t++;\n            } else {\n                int opsLeft = 5000 - (int)ops.size();\n                MovePlan mv = decideMove(st, t, w, rng, opsLeft);\n\n                ops.push_back({mv.v, mv.d + 1});\n                st.moveSuffix(mv.s, mv.start, mv.d);\n                energy += (long long)mv.len + 1;\n            }\n\n            if ((int)ops.size() > 5000) break;\n        }\n\n        return Result{energy, std::move(ops)};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> initStacks(M);\n    for (int i = 0; i < M; i++) {\n        initStacks[i].resize(n / m);\n        for (int j = 0; j < n / m; j++) cin >> initStacks[i][j];\n    }\n\n    Solver solver(initStacks);\n\n    Weights base;\n\n    auto t0 = chrono::high_resolution_clock::now();\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result best;\n    best.energy = (1LL<<60);\n\n    int trials = 0;\n    while (true) {\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - t0).count();\n        if (elapsed > 1.93) break;\n\n        Weights w = base;\n\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)trials;\n        uint64_t rng = seed;\n\n        auto rand01 = [&]() -> double {\n            return (double)(xorshift64(rng) % 1000000) / 1000000.0;\n        };\n        auto mult = [&](double x, double lo, double hi) {\n            return x * (lo + (hi - lo) * rand01());\n        };\n\n        if (trials > 0) {\n            w.wHeight = mult(w.wHeight, 0.7, 1.4);\n            w.wMinUrg = mult(w.wMinUrg, 0.75, 1.35);\n            w.wTopUrg = mult(w.wTopUrg, 0.75, 1.35);\n            w.wMinAtTopExtra = mult(w.wMinAtTopExtra, 0.75, 1.45);\n\n            w.badTopBase = mult(w.badTopBase, 0.7, 1.4);\n            w.badTopPerCnt = mult(w.badTopPerCnt, 0.7, 1.6);\n\n            w.badMinBase = mult(w.badMinBase, 0.7, 1.5);\n            w.badMinPerCnt = mult(w.badMinPerCnt, 0.7, 1.6);\n\n            w.emptyReserve = mult(w.emptyReserve, 0.6, 1.6);\n\n            // vary lookahead slightly\n            double r = rand01();\n            if (r < 0.25) w.lookahead = 12;\n            else if (r < 0.55) w.lookahead = 14;\n            else w.lookahead = 16;\n\n            // chunking aggressiveness\n            double r2 = rand01();\n            if (r2 < 0.30) w.cmax = 5;\n            else if (r2 < 0.70) w.cmax = 6;\n            else w.cmax = 7;\n\n            // destination candidates\n            double r3 = rand01();\n            if (r3 < 0.30) w.destCand = 5;\n            else if (r3 < 0.75) w.destCand = 6;\n            else w.destCand = 7;\n        }\n\n        Result cur = solver.run(w, seed);\n        if ((int)cur.ops.size() <= 5000 && cur.energy < best.energy) {\n            best = std::move(cur);\n        }\n\n        trials++;\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << \" \" << i << \"\\n\";\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline char oppositeDir(char c){\n    if(c=='U') return 'D';\n    if(c=='D') return 'U';\n    if(c=='L') return 'R';\n    return 'L';\n}\nstatic inline int dirId(char c){\n    if(c=='U') return 0;\n    if(c=='D') return 1;\n    if(c=='L') return 2;\n    return 3;\n}\nstatic const char DIRCH[4] = {'U','D','L','R'};\n\nstruct Timer{\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()){}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct XorShift{\n    uint64_t x=88172645463325252ull;\n    explicit XorShift(uint64_t seed=0){ if(seed) x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int nextInt(int lo,int hi){\n        return lo + (int)(next() % (uint64_t)(hi-lo+1));\n    }\n};\n\nstruct Edge {\n    int to;\n    int eid;\n    char mv;\n};\n\nstruct AnalysisResult{\n    bool ok=false;\n    long long sumSq=(1LL<<62);\n    long double metric=1e100L;\n    vector<int> pos;          // size L+1, pos[0]=0, pos[i+1]=arrival after i-th move\n    vector<int> first, last;\n    vector<int> bestGapLen;\n    vector<int> bestGapStart;\n};\n\nstruct Solver{\n    int N,V;\n    vector<string> h,v;\n    vector<int> d;\n    vector<array<int,4>> nxt;\n\n    // undirected graph (same as nxt but with eid/move)\n    vector<vector<Edge>> g;\n    vector<int> eu, ev;\n    int E = 0;\n\n    // all-pairs distances\n    vector<uint16_t> distAll;\n    static constexpr uint16_t INF = 65535;\n\n    inline uint16_t distUV(int u,int v) const { return distAll[(size_t)u*V + v]; }\n\n    // BCC decomposition (edge-stack)\n    vector<int> disc, low;\n    vector<char> isArt;\n    vector<int> estack;\n    vector<vector<int>> bccEdges;\n    vector<vector<int>> bccVerts;\n    vector<int> edgeBcc;           // eid -> block id\n    vector<vector<int>> belongs;   // vertex -> blocks\n    int B=0, A=0;\n    vector<int> artIndex;\n\n    // block-cut tree parent for portal\n    vector<vector<pair<int,int>>> bcTree;\n    vector<int> parentNode, parentVia;\n    vector<int> blockPortal;\n    vector<long long> blockWeight;\n\n    // precomputed short loop tour per heavy block (portal -> ... -> portal, only edges inside block)\n    vector<vector<int>> blockTopNodes;\n    vector<string> blockTour;\n\n    // restricted BFS within a block (used only in precompute)\n    vector<int> rDist, rPrev;\n    vector<char> rPrevMove;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n    int id(int i,int j) const { return i*N + j; }\n\n    void readInput(){\n        cin >> N;\n        V = N*N;\n        h.resize(N-1);\n        v.resize(N);\n        for(int i=0;i<N-1;i++) cin >> h[i];\n        for(int i=0;i<N;i++) cin >> v[i];\n        d.assign(V,0);\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int x; cin >> x;\n            d[id(i,j)] = x;\n        }\n        nxt.assign(V, array<int,4>{-1,-1,-1,-1});\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int u=id(i,j);\n            if(i>0   && h[i-1][j]=='0') nxt[u][0]=id(i-1,j);\n            if(i<N-1 && h[i][j]=='0')   nxt[u][1]=id(i+1,j);\n            if(j>0   && v[i][j-1]=='0') nxt[u][2]=id(i,j-1);\n            if(j<N-1 && v[i][j]=='0')   nxt[u][3]=id(i,j+1);\n        }\n        rDist.assign(V,-1);\n        rPrev.assign(V,-1);\n        rPrevMove.assign(V,0);\n    }\n\n    void buildGraph(){\n        g.assign(V, {});\n        eu.clear(); ev.clear();\n        for(int u=0;u<V;u++){\n            for(int k=0;k<4;k++){\n                int w = nxt[u][k];\n                if(w<0) continue;\n                if(u < w){\n                    int eid = (int)eu.size();\n                    eu.push_back(u);\n                    ev.push_back(w);\n                    char mv = DIRCH[k]; // u->w\n                    g[u].push_back(Edge{w, eid, mv});\n                    g[w].push_back(Edge{u, eid, oppositeDir(mv)});\n                }\n            }\n        }\n        E = (int)eu.size();\n    }\n\n    void precomputeAllPairsDistances(){\n        distAll.assign((size_t)V*V, INF);\n        vector<int> dist(V, -1);\n        deque<int> q;\n        for(int s=0;s<V;s++){\n            fill(dist.begin(), dist.end(), -1);\n            dist[s]=0;\n            q.clear();\n            q.push_back(s);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                int du=dist[u];\n                for(auto &e: g[u]){\n                    int w=e.to;\n                    if(dist[w]!=-1) continue;\n                    dist[w]=du+1;\n                    q.push_back(w);\n                }\n            }\n            size_t base=(size_t)s*V;\n            for(int vtx=0; vtx<V; vtx++){\n                distAll[base+vtx] = (dist[vtx]<0? INF : (uint16_t)dist[vtx]);\n            }\n        }\n    }\n\n    // build shortest path using dist descent (no BFS)\n    string shortestPathMovesByDist(int s,int t) const {\n        if(s==t) return {};\n        uint16_t d0 = distUV(s,t);\n        if(d0==INF) return {};\n        string path;\n        path.reserve(d0);\n        int cur=s;\n        while(cur!=t){\n            uint16_t dc = distUV(cur,t);\n            bool moved=false;\n            for(int k=0;k<4;k++){\n                int nx = nxt[cur][k];\n                if(nx<0) continue;\n                uint16_t dn = distUV(nx,t);\n                if(dn+1==dc){\n                    path.push_back(DIRCH[k]);\n                    cur=nx;\n                    moved=true;\n                    break;\n                }\n            }\n            if(!moved) return {};\n        }\n        return path;\n    }\n    static string reverseOpp(const string& p){\n        string r;\n        r.reserve(p.size());\n        for(int i=(int)p.size()-1;i>=0;i--) r.push_back(oppositeDir(p[i]));\n        return r;\n    }\n\n    // ----- BCC (Tarjan, edge stack) -----\n    void buildBCC(){\n        disc.assign(V,0);\n        low.assign(V,0);\n        isArt.assign(V,0);\n        edgeBcc.assign(E,-1);\n        bccEdges.clear();\n        bccVerts.clear();\n        estack.clear();\n        belongs.assign(V,{});\n        int tim=0;\n\n        auto addBCCfromEdges = [&](const vector<int>& edges){\n            if(edges.empty()) return;\n            int bid=(int)bccEdges.size();\n            bccEdges.push_back(edges);\n            for(int e: edges) edgeBcc[e]=bid;\n\n            vector<int> verts;\n            verts.reserve(edges.size()*2);\n            for(int e: edges){\n                verts.push_back(eu[e]);\n                verts.push_back(ev[e]);\n            }\n            sort(verts.begin(), verts.end());\n            verts.erase(unique(verts.begin(), verts.end()), verts.end());\n            bccVerts.push_back(verts);\n            for(int vtx: verts) belongs[vtx].push_back(bid);\n        };\n\n        auto popUntil = [&](int stopEid){\n            vector<int> edges;\n            while(true){\n                int e=estack.back(); estack.pop_back();\n                edges.push_back(e);\n                if(e==stopEid) break;\n            }\n            addBCCfromEdges(edges);\n        };\n        auto popAll = [&](){\n            vector<int> edges;\n            while(!estack.empty()){\n                edges.push_back(estack.back());\n                estack.pop_back();\n            }\n            addBCCfromEdges(edges);\n        };\n\n        function<void(int,int)> dfs = [&](int u,int peid){\n            disc[u]=low[u]=++tim;\n            int child=0;\n            for(auto &e: g[u]){\n                int vtx=e.to;\n                if(disc[vtx]==0){\n                    child++;\n                    estack.push_back(e.eid);\n                    dfs(vtx, e.eid);\n                    low[u]=min(low[u], low[vtx]);\n                    if(low[vtx]>=disc[u]){\n                        if(peid!=-1 || child>1) isArt[u]=1;\n                        popUntil(e.eid);\n                    }\n                }else if(e.eid!=peid && disc[vtx]<disc[u]){\n                    low[u]=min(low[u], disc[vtx]);\n                    estack.push_back(e.eid);\n                }\n            }\n        };\n\n        for(int s=0;s<V;s++){\n            if(disc[s]!=0) continue;\n            dfs(s,-1);\n            popAll();\n        }\n\n        B=(int)bccEdges.size();\n        artIndex.assign(V,-1);\n        A=0;\n        for(int vtx=0; vtx<V; vtx++){\n            if(isArt[vtx]) artIndex[vtx]=A++;\n        }\n    }\n\n    void buildBlockCutTree(){\n        int nodeCount=B+A;\n        bcTree.assign(nodeCount,{});\n        for(int bid=0; bid<B; bid++){\n            for(int vtx: bccVerts[bid]){\n                if(!isArt[vtx]) continue;\n                int an=B+artIndex[vtx];\n                bcTree[bid].push_back({an, vtx});\n                bcTree[an].push_back({bid, vtx});\n            }\n        }\n\n        int root;\n        if(isArt[0]) root=B+artIndex[0];\n        else root = belongs[0].empty()? 0 : belongs[0][0];\n\n        parentNode.assign(nodeCount,-1);\n        parentVia.assign(nodeCount,-1);\n        deque<int> q;\n        parentNode[root]=root;\n        parentVia[root]=0;\n        q.push_back(root);\n        while(!q.empty()){\n            int cur=q.front(); q.pop_front();\n            for(auto [nx, via]: bcTree[cur]){\n                if(parentNode[nx]!=-1) continue;\n                parentNode[nx]=cur;\n                parentVia[nx]=via;\n                q.push_back(nx);\n            }\n        }\n\n        blockPortal.assign(B,0);\n        for(int bid=0; bid<B; bid++){\n            if(parentNode[bid]==bid) blockPortal[bid]=0;\n            else blockPortal[bid]=parentVia[bid];\n        }\n\n        blockWeight.assign(B,0);\n        for(int bid=0; bid<B; bid++){\n            long long w=0;\n            for(int vtx: bccVerts[bid]) if(!isArt[vtx]) w += d[vtx];\n            if(w==0) for(int vtx: bccVerts[bid]) w += d[vtx];\n            blockWeight[bid]=w;\n        }\n    }\n\n    // restricted BFS inside a block\n    void bfsRestricted(int s,int bid){\n        fill(rDist.begin(), rDist.end(), -1);\n        fill(rPrev.begin(), rPrev.end(), -1);\n        deque<int> q;\n        rDist[s]=0;\n        q.push_back(s);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            for(auto &e: g[u]){\n                if(edgeBcc[e.eid]!=bid) continue;\n                int w=e.to;\n                if(rDist[w]!=-1) continue;\n                rDist[w]=rDist[u]+1;\n                rPrev[w]=u;\n                rPrevMove[w]=e.mv;\n                q.push_back(w);\n            }\n        }\n    }\n    string restrictedPath(int s,int t){\n        if(s==t) return {};\n        if(rDist[t]<0) return {};\n        string rev;\n        int cur=t;\n        while(cur!=s){\n            rev.push_back(rPrevMove[cur]);\n            cur=rPrev[cur];\n            if(cur<0) return {};\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    void precomputeBlockTours(){\n        blockTopNodes.assign(B,{});\n        blockTour.assign(B,\"\");\n\n        vector<pair<long long,int>> ord;\n        ord.reserve(B);\n        for(int bid=0; bid<B; bid++) ord.push_back({blockWeight[bid], bid});\n        sort(ord.begin(), ord.end(), greater<>());\n\n        int H=min<int>(25,(int)ord.size());\n        vector<char> heavy(B,0);\n        for(int i=0;i<H;i++) heavy[ord[i].second]=1;\n\n        for(int bid=0; bid<B; bid++){\n            if(!heavy[bid]) continue;\n            int portal=blockPortal[bid];\n            bool okPortal=false;\n            for(int vtx: bccVerts[bid]) if(vtx==portal){ okPortal=true; break; }\n            if(!okPortal) continue;\n\n            vector<int> verts=bccVerts[bid];\n            sort(verts.begin(), verts.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n\n            // top nodes in block\n            int K=min<int>(14,(int)verts.size());\n            verts.resize(K);\n            if(find(verts.begin(), verts.end(), portal)==verts.end()) verts.push_back(portal);\n            sort(verts.begin(), verts.end());\n            verts.erase(unique(verts.begin(), verts.end()), verts.end());\n            sort(verts.begin(), verts.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n            blockTopNodes[bid]=verts;\n\n            // greedy nearest neighbor tour inside block (short)\n            vector<int> targets=verts;\n            targets.erase(remove(targets.begin(), targets.end(), portal), targets.end());\n\n            string tour;\n            int cur=portal;\n            while(!targets.empty()){\n                bfsRestricted(cur, bid);\n                int best=-1, bestDist=INT_MAX, bestD=-1;\n                for(int t: targets){\n                    int dist=rDist[t];\n                    if(dist<0) continue;\n                    if(dist<bestDist || (dist==bestDist && d[t]>bestD)){\n                        bestDist=dist; bestD=d[t]; best=t;\n                    }\n                }\n                if(best==-1) break;\n                string p = restrictedPath(cur, best);\n                if(p.empty() && cur!=best) break;\n                tour += p;\n                cur = best;\n                targets.erase(remove(targets.begin(), targets.end(), best), targets.end());\n                if((int)tour.size()>2800) break;\n            }\n            bfsRestricted(cur, bid);\n            string back = restrictedPath(cur, portal);\n            if(back.empty() && cur!=portal) continue;\n            tour += back;\n\n            if((int)tour.size()<=3200) blockTour[bid]=tour;\n        }\n    }\n\n    // ----- Base construction: spanning tree + Euler + first-visit order + shortest paths -----\n    void buildSpanningTree(vector<int>& parent, vector<char>& parentDir, vector<int>& order,\n                           XorShift& rng, int gamma, int noiseScale){\n        parent.assign(V,-1);\n        parentDir.assign(V,'?');\n        vector<int> depth(V,0);\n        vector<char> vis(V,0);\n        order.clear(); order.reserve(V);\n\n        struct Cand{ int key; int p; int x; char dir; };\n        struct Cmp{ bool operator()(const Cand& a,const Cand& b) const { return a.key < b.key; } };\n        priority_queue<Cand, vector<Cand>, Cmp> pq;\n\n        auto pushNei = [&](int u){\n            int du=depth[u];\n            for(int k=0;k<4;k++){\n                int w=nxt[u][k];\n                if(w<0||vis[w]) continue;\n                int noise = noiseScale ? rng.nextInt(0, noiseScale) : 0;\n                int key = d[w]*1024 - gamma*(du+1)*1024 + noise;\n                pq.push(Cand{key,u,w,DIRCH[k]});\n            }\n        };\n\n        vis[0]=1;\n        order.push_back(0);\n        pushNei(0);\n\n        while((int)order.size()<V){\n            if(pq.empty()) break;\n            auto c=pq.top(); pq.pop();\n            if(vis[c.x]) continue;\n            vis[c.x]=1;\n            parent[c.x]=c.p;\n            parentDir[c.x]=c.dir;\n            depth[c.x]=depth[c.p]+1;\n            order.push_back(c.x);\n            pushNei(c.x);\n        }\n\n        if((int)order.size()<V){\n            // BFS fallback\n            parent.assign(V,-1);\n            parentDir.assign(V,'?');\n            order.clear();\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent[w]=u;\n                    parentDir[w]=DIRCH[k];\n                    q.push_back(w);\n                    order.push_back(w);\n                }\n            }\n        }\n    }\n\n    string buildEulerRoute(const vector<int>& parent, const vector<char>& parentDir,\n                           const vector<int>& order, XorShift& rng, int childNoise){\n        vector<vector<int>> children(V);\n        for(int x=1;x<V;x++){\n            int p=parent[x];\n            if(p>=0) children[p].push_back(x);\n        }\n        vector<long long> sub(V);\n        for(int i=0;i<V;i++) sub[i]=d[i];\n        for(int idx=(int)order.size()-1; idx>=1; --idx){\n            int x=order[idx];\n            int p=parent[x];\n            if(p>=0) sub[p]+=sub[x];\n        }\n        for(int u=0;u<V;u++){\n            auto &ch=children[u];\n            sort(ch.begin(), ch.end(), [&](int a,int b){\n                long long ka=sub[a]*1024 + d[a]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                long long kb=sub[b]*1024 + d[b]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                if(ka!=kb) return ka>kb;\n                return a<b;\n            });\n        }\n        string route;\n        route.reserve(2*(V-1)+10);\n        function<void(int)> dfs=[&](int u){\n            for(int x: children[u]){\n                route.push_back(parentDir[x]);\n                dfs(x);\n                route.push_back(oppositeDir(parentDir[x]));\n            }\n        };\n        dfs(0);\n        return route;\n    }\n\n    bool simulatePositions(const string& route, vector<int>& pos) const {\n        int L=(int)route.size();\n        pos.assign(L+1,0);\n        int cur=0;\n        for(int i=0;i<L;i++){\n            int k=dirId(route[i]);\n            int nx=nxt[cur][k];\n            if(nx<0) return false;\n            cur=nx;\n            pos[i+1]=cur;\n        }\n        return cur==0;\n    }\n\n    vector<int> firstVisitOrderFromEuler(const string& euler) const {\n        vector<int> pos;\n        simulatePositions(euler, pos);\n        vector<char> seen(V,0);\n        vector<int> ord;\n        ord.reserve(V+1);\n        seen[0]=1;\n        ord.push_back(0);\n        for(int i=1;i<(int)pos.size();i++){\n            int vtx=pos[i];\n            if(!seen[vtx]){\n                seen[vtx]=1;\n                ord.push_back(vtx);\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++) if(!seen[vtx]) ord.push_back(vtx);\n        ord.push_back(0);\n        return ord;\n    }\n\n    string buildRouteFromOrder(const vector<int>& ord, int maxLen=100000) const {\n        string route;\n        for(int i=0;i+1<(int)ord.size();i++){\n            string p=shortestPathMovesByDist(ord[i], ord[i+1]);\n            if(p.empty() && ord[i]!=ord[i+1]) return {};\n            if((int)route.size() + (int)p.size() > maxLen) return {};\n            route += p;\n        }\n        return route;\n    }\n\n    // ----- Metric (objective-equivalent) -----\n    AnalysisResult analyzeRoute(const string& route) const {\n        AnalysisResult res;\n        int L=(int)route.size();\n        if(L<=0) return res;\n        if(!simulatePositions(route, res.pos)) return res;\n\n        res.first.assign(V,-1);\n        res.last.assign(V,-1);\n        res.bestGapLen.assign(V,-1);\n        res.bestGapStart.assign(V,0);\n\n        long long sumSq=0;\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=res.pos[i+1];\n            if(res.first[vtx]==-1){\n                res.first[vtx]=res.last[vtx]=t;\n            }else{\n                int gap=t-res.last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                if(gap > res.bestGapLen[vtx]){\n                    res.bestGapLen[vtx]=gap;\n                    res.bestGapStart[vtx]=res.last[vtx];\n                }\n                res.last[vtx]=t;\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++){\n            if(res.first[vtx]==-1) return res; // unvisited\n            int gap=(res.first[vtx]+L)-res.last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n            if(gap > res.bestGapLen[vtx]){\n                res.bestGapLen[vtx]=gap;\n                res.bestGapStart[vtx]=res.last[vtx];\n            }\n        }\n        res.sumSq=sumSq;\n        res.metric=(long double)sumSq/(long double)L;\n        res.ok=true;\n        return res;\n    }\n\n    long double computeMetric(const string& route, vector<int>& first, vector<int>& last) const {\n        int L=(int)route.size();\n        if(L<=0) return 1e100L;\n        vector<int> pos;\n        if(!simulatePositions(route, pos)) return 1e100L;\n\n        fill(first.begin(), first.end(), -1);\n        fill(last.begin(), last.end(), -1);\n        long long sumSq=0;\n\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=pos[i+1];\n            if(first[vtx]==-1) first[vtx]=last[vtx]=t;\n            else{\n                int gap=t-last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                last[vtx]=t;\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++){\n            if(first[vtx]==-1) return 1e100L;\n            int gap=(first[vtx]+L)-last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n        }\n        return (long double)sumSq/(long double)L;\n    }\n\n    // insertion position near midpoint of rep's best gap, minimizing dist(pos[p], target)\n    pair<int,int> chooseInsertPosNearGap(const AnalysisResult& ar, int repVtx, int targetVtx) const {\n        int L=(int)ar.pos.size()-1;\n        int startT=ar.bestGapStart[repVtx];\n        int len=ar.bestGapLen[repVtx];\n        long long midT=(long long)startT + len/2;\n        int baseP=(int)((midT + 1) % L);\n\n        int W=min(50, max(3, len/5));\n        int bestP=baseP;\n        int bestDist=INT_MAX;\n        int bestAbs=INT_MAX;\n\n        for(int off=-W; off<=W; off++){\n            int p=baseP+off;\n            p%=L; if(p<0) p+=L;\n            int at=ar.pos[p];\n            uint16_t dist=distUV(at, targetVtx);\n            if(dist==INF) continue;\n            int aoff=abs(off);\n            if((int)dist < bestDist || ((int)dist==bestDist && aoff < bestAbs)){\n                bestDist=(int)dist;\n                bestAbs=aoff;\n                bestP=p;\n            }\n        }\n        return {bestP, bestDist};\n    }\n\n    // ----- Local improvement: vertex detours + block loops -----\n    void improveByDetours(string& route, Timer& timer, double endTime){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        // blocks with usable tours\n        vector<int> tourBlocks;\n        for(int bid=0; bid<B; bid++){\n            if(!blockTour[bid].empty()) tourBlocks.push_back(bid);\n        }\n\n        while(timer.elapsed() < endTime){\n            AnalysisResult ar = analyzeRoute(route);\n            if(!ar.ok) break;\n            long double curMetric = ar.metric;\n            int L=(int)route.size();\n            if(L>=100000) break;\n\n            struct Cand{\n                int type; // 0 vertex, 1 block\n                int key;  // vtx or bid\n                int insertPos;\n                long long estBenefit;\n                int estAddLen;\n                long double ratio;\n            };\n            vector<Cand> cands;\n            cands.reserve(128);\n\n            // --- vertex candidates ---\n            vector<pair<long long,int>> vkeys;\n            vkeys.reserve(V);\n            for(int vtx=0; vtx<V; vtx++){\n                int ggap=ar.bestGapLen[vtx];\n                if(ggap<=1) continue;\n                vkeys.push_back({1LL*d[vtx]*ggap*ggap, vtx});\n            }\n            if(vkeys.empty()) break;\n            int Kv=min<int>(45,(int)vkeys.size());\n            nth_element(vkeys.begin(), vkeys.begin()+Kv, vkeys.end(),\n                        [&](auto& a, auto& b){ return a.first > b.first; });\n            vkeys.resize(Kv);\n            sort(vkeys.begin(), vkeys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n            for(auto [_, vtx] : vkeys){\n                if(timer.elapsed() >= endTime) break;\n                int ggap=ar.bestGapLen[vtx];\n                auto [p, dist] = chooseInsertPosNearGap(ar, vtx, vtx);\n                if(dist<=0) continue;\n                int addLen = 2*dist;\n                if(L + addLen > 100000) continue;\n                int a=ggap/2, b=ggap-a;\n                long long benefit = 1LL*d[vtx]*(1LL*ggap*ggap - 1LL*a*a - 1LL*b*b);\n                if(benefit<=0) continue;\n                cands.push_back(Cand{0, vtx, p, benefit, addLen, (long double)benefit/addLen});\n            }\n\n            // --- block candidates (dynamic hotness based on current gaps) ---\n            vector<pair<long long,int>> bkeys;\n            bkeys.reserve(tourBlocks.size());\n            for(int bid: tourBlocks){\n                long long hot=0;\n                for(int u: blockTopNodes[bid]){\n                    int ggap=ar.bestGapLen[u];\n                    hot += 1LL*d[u]*ggap*ggap;\n                }\n                if(hot>0) bkeys.push_back({hot, bid});\n            }\n            int Kb=min<int>(6,(int)bkeys.size());\n            if(Kb>0){\n                nth_element(bkeys.begin(), bkeys.begin()+Kb, bkeys.end(),\n                            [&](auto& a, auto& b){ return a.first > b.first; });\n                bkeys.resize(Kb);\n                sort(bkeys.begin(), bkeys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n                for(auto [_, bid] : bkeys){\n                    if(timer.elapsed() >= endTime) break;\n                    int portal=blockPortal[bid];\n                    const string& tour = blockTour[bid];\n\n                    // representative in block: max d*gap^2\n                    int rep=portal;\n                    long long repKey=-1;\n                    for(int u: blockTopNodes[bid]){\n                        int ggap=ar.bestGapLen[u];\n                        long long kk=1LL*d[u]*ggap*ggap;\n                        if(kk>repKey){ repKey=kk; rep=u; }\n                    }\n                    if(repKey<=0) continue;\n\n                    auto [p, distToPortal] = chooseInsertPosNearGap(ar, rep, portal);\n                    if(distToPortal<=0) continue;\n                    int addLen = 2*distToPortal + (int)tour.size();\n                    if(L + addLen > 100000) continue;\n\n                    long long benefitSum=0;\n                    for(int u: blockTopNodes[bid]){\n                        int ggap=ar.bestGapLen[u];\n                        if(ggap<=1) continue;\n                        int a=ggap/2, b=ggap-a;\n                        benefitSum += 1LL*d[u]*(1LL*ggap*ggap - 1LL*a*a - 1LL*b*b);\n                    }\n                    if(benefitSum<=0) continue;\n\n                    cands.push_back(Cand{1, bid, p, benefitSum, addLen, (long double)benefitSum/addLen});\n                }\n            }\n\n            if(cands.empty()) break;\n            sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                return a.ratio > b.ratio;\n            });\n\n            int M=min<int>(14,(int)cands.size());\n            long double bestMetric=curMetric;\n            int bestIdx=-1;\n            string bestDet;\n\n            for(int i=0;i<M;i++){\n                if(timer.elapsed() >= endTime) break;\n                const auto& c=cands[i];\n                int p=c.insertPos;\n                int startV=ar.pos[p];\n\n                string det;\n                if(c.type==0){\n                    int vtx=c.key;\n                    string go = shortestPathMovesByDist(startV, vtx);\n                    if(go.empty() && startV!=vtx) continue;\n                    det.reserve(go.size()*2);\n                    det += go;\n                    det += reverseOpp(go);\n                }else{\n                    int bid=c.key;\n                    int portal=blockPortal[bid];\n                    const string& tour=blockTour[bid];\n                    string go = shortestPathMovesByDist(startV, portal);\n                    if(go.empty() && startV!=portal) continue;\n                    det.reserve(go.size()*2 + tour.size());\n                    det += go;\n                    det += tour;\n                    det += reverseOpp(go);\n                }\n\n                if((int)route.size() + (int)det.size() > 100000) continue;\n\n                route.insert((size_t)p, det);\n                long double met = computeMetric(route, tmpFirst, tmpLast);\n                route.erase((size_t)p, det.size());\n\n                if(met + 1e-18L < bestMetric){\n                    bestMetric=met;\n                    bestIdx=i;\n                    bestDet=std::move(det);\n                }\n            }\n\n            if(bestIdx==-1) break;\n            route.insert((size_t)cands[bestIdx].insertPos, bestDet);\n        }\n    }\n\n    // Simple backtrack removal, metric-checked\n    void simplifyBacktracks(string& route, Timer& timer, double endTime){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n        int tries=0;\n        while(timer.elapsed() < endTime && tries < 200){\n            tries++;\n            vector<int> pos;\n            if(!simulatePositions(route, pos)) return;\n            int L=(int)route.size();\n\n            long double base = computeMetric(route, tmpFirst, tmpLast);\n            bool improved=false;\n\n            for(int i=0;i+1<L;i++){\n                if(timer.elapsed() >= endTime) break;\n                char a=route[i], b=route[i+1];\n                if(oppositeDir(a)!=b) continue;\n\n                // try remove two chars\n                string cand;\n                cand.reserve(L-2);\n                cand.append(route.begin(), route.begin()+i);\n                cand.append(route.begin()+i+2, route.end());\n\n                long double met = computeMetric(cand, tmpFirst, tmpLast);\n                if(met + 1e-18L < base){\n                    route.swap(cand);\n                    improved=true;\n                    break;\n                }\n            }\n            if(!improved) break;\n        }\n    }\n\n    void solve(){\n        Timer timer;\n        double TL=1.95;\n        XorShift rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        buildGraph();\n        precomputeAllPairsDistances();\n        buildBCC();\n        buildBlockCutTree();\n        precomputeBlockTours();\n\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        string bestRoute;\n        long double bestMetric=1e100L;\n\n        int starts=9;\n        vector<int> parent, order;\n        vector<char> parentDir;\n\n        for(int s=0;s<starts;s++){\n            if(timer.elapsed() > TL) break;\n\n            int gamma = 8 + (s%5)*4;\n            int noiseScale = 7000 + s*2500;\n            int childNoise  = 1200 + s*900;\n\n            buildSpanningTree(parent, parentDir, order, rng, gamma, noiseScale);\n            string euler = buildEulerRoute(parent, parentDir, order, rng, childNoise);\n\n            vector<int> ord = firstVisitOrderFromEuler(euler);\n            string route = buildRouteFromOrder(ord, 100000);\n            if(route.empty()) route = euler;\n\n            // time slice\n            double now=timer.elapsed();\n            double remain=max(0.0, TL-now);\n            double per = remain / max(1, starts - s);\n            double endTime = min(TL, now + per*0.94);\n\n            improveByDetours(route, timer, endTime);\n            simplifyBacktracks(route, timer, min(TL, endTime + 0.03));\n\n            long double met = computeMetric(route, tmpFirst, tmpLast);\n            if(met < bestMetric){\n                bestMetric = met;\n                bestRoute = std::move(route);\n            }\n        }\n\n        if(bestRoute.empty()){\n            // fallback BFS-tree Euler\n            vector<int> parent2(V,-1), order2;\n            vector<char> pd2(V,'?');\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order2.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent2[w]=u;\n                    pd2[w]=DIRCH[k];\n                    q.push_back(w);\n                    order2.push_back(w);\n                }\n            }\n            bestRoute = buildEulerRoute(parent2, pd2, order2, rng, 0);\n        }\n\n        cout << bestRoute << \"\\n\";\n    }\n};\n\nint main(){\n    Solver s;\n    s.readInput();\n    s.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static const auto t0 = steady_clock::now();\n    return duration<double>(steady_clock::now() - t0).count();\n}\n\nstruct Candidate {\n    int approx;\n    vector<int> perm;\n};\n\nstatic inline void add_pool(vector<Candidate>& pool, int K, int approx, const vector<int>& perm) {\n    if ((int)pool.size() < K) {\n        pool.push_back({approx, perm});\n        return;\n    }\n    int worst = 0;\n    for (int i = 1; i < (int)pool.size(); i++) if (pool[i].approx > pool[worst].approx) worst = i;\n    if (approx < pool[worst].approx) pool[worst] = {approx, perm};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; i++) cin >> grid[i];\n    vector<string> t(M);\n    for (int i = 0; i < M; i++) cin >> t[i];\n\n    // Contest fixed: N=15\n    constexpr int NFIX = 15;\n    constexpr int V = NFIX * NFIX; // 225\n\n    auto cell_id = [&](int r, int c) { return r * N + c; };\n    int startCell = cell_id(si, sj);\n\n    // letter at each cell\n    array<int, V> letterAtCell{};\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int id = cell_id(r, c);\n        letterAtCell[id] = grid[r][c] - 'A';\n    }\n\n    // cells by letter\n    array<vector<int>, 26> cellsByLetter;\n    for (int id = 0; id < N * N; id++) cellsByLetter[letterAtCell[id]].push_back(id);\n\n    int maxOcc = 0;\n    for (int c = 0; c < 26; c++) maxOcc = max(maxOcc, (int)cellsByLetter[c].size());\n\n    // dist between all cells\n    vector<array<uint8_t, V>> distCell(V);\n    for (int a = 0; a < V; a++) {\n        int ar = a / N, ac = a % N;\n        for (int b = 0; b < V; b++) {\n            int br = b / N, bc = b % N;\n            distCell[a][b] = (uint8_t)(abs(ar - br) + abs(ac - bc));\n        }\n    }\n\n    // words as ints\n    vector<array<int,5>> w(M);\n    vector<int> lastL(M);\n    for (int i = 0; i < M; i++) {\n        for (int k = 0; k < 5; k++) w[i][k] = t[i][k] - 'A';\n        lastL[i] = w[i][4];\n    }\n\n    auto max_overlap = [&](int a, int b) -> int {\n        for (int l = 4; l >= 1; --l) {\n            bool ok = true;\n            for (int i = 0; i < l; i++) {\n                if (t[a][5 - l + i] != t[b][i]) { ok = false; break; }\n            }\n            if (ok) return l;\n        }\n        return 0;\n    };\n\n    // max overlap per pair\n    vector<vector<uint8_t>> ovMax(M, vector<uint8_t>(M, 0));\n    for (int i = 0; i < M; i++) for (int j = 0; j < M; j++) if (i != j) {\n        ovMax[i][j] = (uint8_t)max_overlap(i, j);\n    }\n\n    // ---- Precompute word typing costs for approximation ----\n    vector<int> dp(maxOcc), ndp(maxOcc);\n\n    auto cost_type_from_cell = [&](int idx, int sCell, int from) -> int {\n        if (from >= 5) return 0;\n        const auto &ww = w[idx];\n\n        const auto &L0 = cellsByLetter[ww[from]];\n        int prevSize = (int)L0.size();\n        for (int i = 0; i < prevSize; i++) dp[i] = (int)distCell[sCell][L0[i]] + 1;\n\n        for (int k = from + 1; k < 5; k++) {\n            const auto &Lprev = cellsByLetter[ww[k-1]];\n            const auto &Lcur  = cellsByLetter[ww[k]];\n            int curSize = (int)Lcur.size();\n\n            for (int i = 0; i < curSize; i++) {\n                int best = INT_MAX;\n                int ccell = Lcur[i];\n                for (int j = 0; j < prevSize; j++) {\n                    int pcell = Lprev[j]; // dp[j] corresponds to this occurrence\n                    int cand = dp[j] + (int)distCell[pcell][ccell] + 1;\n                    if (cand < best) best = cand;\n                }\n                ndp[i] = best;\n            }\n            for (int i = 0; i < curSize; i++) dp[i] = ndp[i];\n            prevSize = curSize;\n        }\n\n        int best = INT_MAX;\n        for (int i = 0; i < prevSize; i++) best = min(best, dp[i]);\n        return best;\n    };\n\n    vector<int> startCostWord(M, 0);\n    vector<array<int,26>> fromLetterCost(M);\n    vector<array<int,5>> overlapSuffixCost(M);\n    vector<int> fullFromCell(V);\n\n    for (int i = 0; i < M; i++) {\n        fromLetterCost[i].fill(INT_MAX);\n        overlapSuffixCost[i].fill(INT_MAX);\n\n        for (int s = 0; s < V; s++) fullFromCell[s] = cost_type_from_cell(i, s, 0);\n        startCostWord[i] = fullFromCell[startCell];\n\n        for (int s = 0; s < V; s++) {\n            int x = letterAtCell[s];\n            fromLetterCost[i][x] = min(fromLetterCost[i][x], fullFromCell[s]);\n        }\n\n        for (int l = 1; l <= 4; l++) {\n            int prevLetter = w[i][l-1];\n            int best = INT_MAX;\n            for (int s : cellsByLetter[prevLetter]) best = min(best, cost_type_from_cell(i, s, l));\n            overlapSuffixCost[i][l] = best;\n        }\n    }\n\n    auto build_edgeCost = [&](int cap) {\n        vector<vector<int>> edge(M, vector<int>(M, 0));\n        for (int a = 0; a < M; a++) for (int b = 0; b < M; b++) if (a != b) {\n            int ov = min<int>(ovMax[a][b], cap);\n            edge[a][b] = (ov == 0 ? fromLetterCost[b][lastL[a]] : overlapSuffixCost[b][ov]);\n        }\n        return edge;\n    };\n\n    // Exact DP cost for a fixed string\n    vector<int> dpPrev(maxOcc), dpCur(maxOcc);\n\n    auto exact_cost_string = [&](const string& S) -> int {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        int prevSize = 0;\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int curSize = (int)layer.size();\n\n            if (k == 0) {\n                for (int i = 0; i < curSize; i++) dpCur[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                for (int i = 0; i < curSize; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    for (int j = 0; j < prevSize; j++) {\n                        int cand = dpPrev[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    dpCur[i] = best;\n                }\n            }\n            for (int i = 0; i < curSize; i++) dpPrev[i] = dpCur[i];\n            prevSize = curSize;\n        }\n\n        int lastSize = (int)cellsByLetter[S.back() - 'A'].size();\n        int best = INF;\n        for (int i = 0; i < lastSize; i++) best = min(best, dpPrev[i]);\n        return best;\n    };\n\n    // Exact DP with reconstruction (final output)\n    auto exact_path_string = [&](const string& S) -> pair<int, vector<int>> {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        vector<vector<int16_t>> parent(L);\n\n        vector<int> dpp, dpc;\n        dpp.reserve(maxOcc);\n        dpc.reserve(maxOcc);\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int mc = (int)layer.size();\n            dpc.assign(mc, INF);\n            parent[k].assign(mc, (int16_t)-1);\n\n            if (k == 0) {\n                for (int i = 0; i < mc; i++) dpc[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                int mp = (int)prevLayer.size();\n                for (int i = 0; i < mc; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    int16_t bestj = -1;\n                    for (int j = 0; j < mp; j++) {\n                        int cand = dpp[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) { best = cand; bestj = (int16_t)j; }\n                    }\n                    dpc[i] = best;\n                    parent[k][i] = bestj;\n                }\n            }\n            dpp.swap(dpc);\n        }\n\n        int bestCost = INF, bestIdx = 0;\n        for (int i = 0; i < (int)dpp.size(); i++) if (dpp[i] < bestCost) {\n            bestCost = dpp[i]; bestIdx = i;\n        }\n\n        vector<int> path(L);\n        int idx = bestIdx;\n        for (int k = L - 1; k >= 0; k--) {\n            int c = S[k] - 'A';\n            path[k] = cellsByLetter[c][idx];\n            idx = parent[k][idx];\n        }\n        return {bestCost, path};\n    };\n\n    // RNG\n    mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    // Build S from permutation with cap and optional randomized overlap\n    auto build_S_from_perm = [&](const vector<int>& P, int capMode, bool randomMode) -> string {\n        string SS;\n        SS.reserve(1600);\n        SS += t[P[0]];\n        for (int i = 1; i < M; i++) {\n            int a = P[i-1], b = P[i];\n            int mx = (int)ovMax[a][b];\n            int cap = min(mx, capMode);\n            int ov = cap;\n            if (randomMode) {\n                // biased random towards larger overlaps\n                if (cap > 0) {\n                    double u = ur(rng);\n                    double denom = (double)((1u << (cap + 1)) - 1u);\n                    double x = u * denom;\n                    double acc = 0;\n                    int k = 0;\n                    for (; k <= cap; k++) {\n                        acc += (double)(1u << k);\n                        if (x < acc) break;\n                    }\n                    ov = k;\n                }\n            }\n            SS.append(t[b].begin() + ov, t[b].end());\n        }\n        return SS;\n    };\n\n    // Approx SA over permutations with O(1) deltas\n    auto run_SA = [&](const vector<vector<int>>& edgeCost, double endTime, int poolK) {\n        auto link_cost = [&](int prev, int cur) -> int {\n            if (cur < 0) return 0;\n            if (prev < 0) return startCostWord[cur];\n            return edgeCost[prev][cur];\n        };\n        auto eval_perm = [&](const vector<int>& P) -> int {\n            long long cost = startCostWord[P[0]];\n            for (int i = 1; i < M; i++) cost += edgeCost[P[i-1]][P[i]];\n            return (int)cost;\n        };\n\n        auto greedy_init = [&]() -> vector<int> {\n            vector<int> P;\n            P.reserve(M);\n            vector<char> used(M, 0);\n            int start = 0;\n            for (int i = 1; i < M; i++) if (startCostWord[i] < startCostWord[start]) start = i;\n            P.push_back(start);\n            used[start] = 1;\n            for (int it = 1; it < M; it++) {\n                int cur = P.back();\n                int best = -1, bestv = INT_MAX;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeCost[cur][j];\n                    if (v < bestv) { bestv = v; best = j; }\n                }\n                used[best] = 1;\n                P.push_back(best);\n            }\n            return P;\n        };\n        auto random_init = [&]() -> vector<int> {\n            vector<int> P(M);\n            iota(P.begin(), P.end(), 0);\n            shuffle(P.begin(), P.end(), rng);\n            return P;\n        };\n\n        auto delta_swap = [&](const vector<int>& P, int i, int j) -> int {\n            if (i == j) return 0;\n            if (i > j) swap(i, j);\n            int a = P[i], b = P[j];\n            auto get = [&](int k) -> int {\n                if (k == i) return b;\n                if (k == j) return a;\n                return P[k];\n            };\n            auto contrib_at = [&](int k, bool after) -> int {\n                if (k < 0 || k >= M) return 0;\n                int cur = after ? get(k) : P[k];\n                int prev = (k == 0 ? -1 : (after ? get(k-1) : P[k-1]));\n                return link_cost(prev, cur);\n            };\n            int oldv=0,newv=0;\n            int idxs[4] = {i, i+1, j, j+1};\n            for (int x = 0; x < 4; x++) {\n                int k = idxs[x];\n                bool dup=false;\n                for (int y = 0; y < x; y++) if (idxs[y]==k) dup=true;\n                if (dup) continue;\n                oldv += contrib_at(k,false);\n                newv += contrib_at(k,true);\n            }\n            return newv-oldv;\n        };\n\n        auto delta_insert = [&](const vector<int>& P, int i, int j) -> int {\n            if (i == j) return 0;\n            int x = P[i];\n            if (i < j) {\n                int A = (i == 0 ? -1 : P[i-1]);\n                int B = P[i+1];\n                int Y = P[j];\n                int Z = (j == M-1 ? -1 : P[j+1]);\n                int d=0;\n                d -= link_cost(A,x);\n                d -= link_cost(x,B);\n                d += link_cost(A,B);\n                if (Z != -1) {\n                    d -= link_cost(Y,Z);\n                    d += link_cost(Y,x);\n                    d += link_cost(x,Z);\n                } else {\n                    d += link_cost(Y,x);\n                }\n                return d;\n            } else {\n                int A = (j == 0 ? -1 : P[j-1]);\n                int B = P[j];\n                int C = P[i-1];\n                int D = (i == M-1 ? -1 : P[i+1]);\n                int d=0;\n                d -= link_cost(A,B);\n                d += link_cost(A,x);\n                d += link_cost(x,B);\n                d -= link_cost(C,x);\n                if (D != -1) {\n                    d -= link_cost(x,D);\n                    d += link_cost(C,D);\n                }\n                return d;\n            }\n        };\n\n        auto delta_block = [&](const vector<int>& P, int l, int r, int p) -> int {\n            if (l > r) swap(l,r);\n            if (p >= l && p <= r+1) return 0;\n            int A = (l==0 ? -1 : P[l-1]);\n            int B = P[l];\n            int C = P[r];\n            int D = (r==M-1 ? -1 : P[r+1]);\n            int E,F;\n            if (p==0) { E=-1; F=P[0]; }\n            else if (p==M) { E=P[M-1]; F=-1; }\n            else { E=P[p-1]; F=P[p]; }\n            int oldv = link_cost(A,B) + link_cost(C,D) + link_cost(E,F);\n            int newv = link_cost(A,D) + link_cost(E,B) + link_cost(C,F);\n            return newv-oldv;\n        };\n\n        vector<Candidate> pool;\n        int restart = 0;\n        while (now_sec() < endTime) {\n            restart++;\n            vector<int> P = (restart % 3 == 1 ? greedy_init() : random_init());\n            int curCost = eval_perm(P);\n            int bestLocal = curCost;\n            vector<int> bestP = P;\n\n            double sliceStart = now_sec();\n            double sliceEnd = min(endTime, sliceStart + 0.20);\n\n            const double Tbegin = 30.0;\n            const double Tend   = 0.30;\n\n            while (now_sec() < sliceEnd) {\n                double prog = (now_sec()-sliceStart) / max(1e-9, (sliceEnd-sliceStart));\n                double temp = Tbegin * pow(Tend / Tbegin, prog);\n\n                double r = ur(rng);\n                int d = 0;\n\n                if (r < 0.55) {\n                    int i = (int)(ur(rng) * M);\n                    int j = (int)(ur(rng) * M);\n                    while (j == i) j = (int)(ur(rng) * M);\n                    d = delta_swap(P, i, j);\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                        swap(P[i], P[j]);\n                        curCost += d;\n                    }\n                } else if (r < 0.85) {\n                    int i = (int)(ur(rng) * M);\n                    int j = (int)(ur(rng) * M);\n                    while (j == i) j = (int)(ur(rng) * M);\n                    d = delta_insert(P, i, j);\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                        if (i < j) rotate(P.begin()+i, P.begin()+i+1, P.begin()+j+1);\n                        else       rotate(P.begin()+j, P.begin()+i,   P.begin()+i+1);\n                        curCost += d;\n                    }\n                } else {\n                    int l = (int)(ur(rng) * M);\n                    int r2 = (int)(ur(rng) * M);\n                    if (l > r2) swap(l, r2);\n                    if (l == r2) continue;\n                    int p = (int)(ur(rng) * (M+1));\n                    if (p >= l && p <= r2+1) continue;\n                    d = delta_block(P, l, r2, p);\n                    if (d == 0) continue;\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                        if (p < l) rotate(P.begin()+p, P.begin()+l,  P.begin()+r2+1);\n                        else       rotate(P.begin()+l, P.begin()+r2+1, P.begin()+p);\n                        curCost += d;\n                    }\n                }\n\n                if (curCost < bestLocal) {\n                    bestLocal = curCost;\n                    bestP = P;\n                }\n            }\n\n            add_pool(pool, poolK, bestLocal, bestP);\n        }\n        return pool;\n    };\n\n    // ---- Time plan ----\n    double t0 = now_sec();\n    double TIME_END = t0 + 1.93;\n\n    // approximate SA budgets\n    double t_sa1_end = t0 + 0.95;\n    double t_sa2_end = t0 + 1.45;\n\n    auto edge4 = build_edgeCost(4);\n    auto edge2 = build_edgeCost(2);\n\n    vector<Candidate> poolAll;\n    auto pool4 = run_SA(edge4, t_sa1_end, 26);\n    for (auto &c : pool4) poolAll.push_back(move(c));\n    auto pool2 = run_SA(edge2, t_sa2_end, 26);\n    for (auto &c : pool2) poolAll.push_back(move(c));\n\n    if (poolAll.empty()) {\n        vector<int> P(M);\n        iota(P.begin(), P.end(), 0);\n        poolAll.push_back({0, P});\n    }\n\n    // ---- Exact evaluation of candidates under several global overlap policies ----\n    int bestExact = INT_MAX;\n    vector<int> bestPerm;\n    int bestCapMode = 4;\n    bool bestRandom = false;\n\n    double t_eval_end = TIME_END - 0.32;\n    for (auto &cand : poolAll) {\n        const auto &P = cand.perm;\n\n        for (int cap : {4, 2, 1, 0}) {\n            // deterministic\n            string S = build_S_from_perm(P, cap, false);\n            int ec = exact_cost_string(S);\n            if (ec < bestExact) {\n                bestExact = ec;\n                bestPerm = P;\n                bestCapMode = cap;\n                bestRandom = false;\n            }\n\n            // small randomized tries (only cap>=2)\n            if (cap >= 2) {\n                for (int rep = 0; rep < 2; rep++) {\n                    string Sr = build_S_from_perm(P, cap, true);\n                    int er = exact_cost_string(Sr);\n                    if (er < bestExact) {\n                        bestExact = er;\n                        bestPerm = P;\n                        bestCapMode = cap;\n                        bestRandom = true;\n                    }\n                }\n            }\n        }\n\n        if (now_sec() > t_eval_end) break;\n    }\n\n    // ---- Exact hill-climb on permutation (safe, only improving) ----\n    // Use edge model matching bestCapMode as a filter for swap/insert/block (O(1) deltas).\n    auto edgeFilter = build_edgeCost(bestCapMode);\n    auto link_cost_f = [&](int prev, int cur) -> int {\n        if (cur < 0) return 0;\n        if (prev < 0) return startCostWord[cur];\n        return edgeFilter[prev][cur];\n    };\n    auto delta_swap_f = [&](const vector<int>& P, int i, int j) -> int {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n        int a = P[i], b = P[j];\n        auto get = [&](int k)->int{\n            if (k==i) return b;\n            if (k==j) return a;\n            return P[k];\n        };\n        auto contrib_at = [&](int k, bool after)->int{\n            if (k<0||k>=M) return 0;\n            int cur = after ? get(k) : P[k];\n            int prev = (k==0 ? -1 : (after ? get(k-1) : P[k-1]));\n            return link_cost_f(prev, cur);\n        };\n        int oldv=0,newv=0;\n        int idxs[4] = {i,i+1,j,j+1};\n        for(int x=0;x<4;x++){\n            int k=idxs[x];\n            bool dup=false;\n            for(int y=0;y<x;y++) if(idxs[y]==k) dup=true;\n            if(dup) continue;\n            oldv += contrib_at(k,false);\n            newv += contrib_at(k,true);\n        }\n        return newv-oldv;\n    };\n    auto delta_insert_f = [&](const vector<int>& P, int i, int j) -> int {\n        if (i == j) return 0;\n        int x = P[i];\n        if (i < j) {\n            int A = (i==0 ? -1 : P[i-1]);\n            int B = P[i+1];\n            int Y = P[j];\n            int Z = (j==M-1 ? -1 : P[j+1]);\n            int d=0;\n            d -= link_cost_f(A,x);\n            d -= link_cost_f(x,B);\n            d += link_cost_f(A,B);\n            if(Z!=-1){\n                d -= link_cost_f(Y,Z);\n                d += link_cost_f(Y,x);\n                d += link_cost_f(x,Z);\n            }else{\n                d += link_cost_f(Y,x);\n            }\n            return d;\n        } else {\n            int A = (j==0 ? -1 : P[j-1]);\n            int B = P[j];\n            int C = P[i-1];\n            int D = (i==M-1 ? -1 : P[i+1]);\n            int d=0;\n            d -= link_cost_f(A,B);\n            d += link_cost_f(A,x);\n            d += link_cost_f(x,B);\n            d -= link_cost_f(C,x);\n            if(D!=-1){\n                d -= link_cost_f(x,D);\n                d += link_cost_f(C,D);\n            }\n            return d;\n        }\n    };\n    auto delta_block_f = [&](const vector<int>& P, int l, int r, int p) -> int {\n        if (l > r) swap(l,r);\n        if (p >= l && p <= r+1) return 0;\n        int A = (l==0 ? -1 : P[l-1]);\n        int B = P[l];\n        int C = P[r];\n        int D = (r==M-1 ? -1 : P[r+1]);\n        int E,F;\n        if (p==0) { E=-1; F=P[0]; }\n        else if (p==M) { E=P[M-1]; F=-1; }\n        else { E=P[p-1]; F=P[p]; }\n        int oldv = link_cost_f(A,B) + link_cost_f(C,D) + link_cost_f(E,F);\n        int newv = link_cost_f(A,D) + link_cost_f(E,B) + link_cost_f(C,F);\n        return newv-oldv;\n    };\n\n    vector<int> curPerm = bestPerm;\n    int curExact = bestExact;\n\n    double t_hill_end = TIME_END - 0.08;\n    while (now_sec() < t_hill_end) {\n        int type = (int)(ur(rng) * 3.0); // 0 swap, 1 insert, 2 block\n        vector<int> backup; // only used for block\n        int approxDelta = 0;\n\n        int i=-1,j=-1,l=-1,r=-1,p=-1;\n\n        if (type == 0) {\n            i = (int)(ur(rng) * M);\n            j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            approxDelta = delta_swap_f(curPerm, i, j);\n            if (approxDelta > 90) continue;\n            swap(curPerm[i], curPerm[j]);\n        } else if (type == 1) {\n            i = (int)(ur(rng) * M);\n            j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            approxDelta = delta_insert_f(curPerm, i, j);\n            if (approxDelta > 90) continue;\n            if (i < j) rotate(curPerm.begin()+i, curPerm.begin()+i+1, curPerm.begin()+j+1);\n            else       rotate(curPerm.begin()+j, curPerm.begin()+i,   curPerm.begin()+i+1);\n        } else {\n            l = (int)(ur(rng) * M);\n            r = (int)(ur(rng) * M);\n            if (l > r) swap(l, r);\n            if (l == r) continue;\n            p = (int)(ur(rng) * (M+1));\n            if (p >= l && p <= r+1) continue;\n            approxDelta = delta_block_f(curPerm, l, r, p);\n            if (approxDelta > 140) continue; // mild filter\n            backup = curPerm;\n            if (p < l) rotate(curPerm.begin()+p, curPerm.begin()+l,   curPerm.begin()+r+1);\n            else       rotate(curPerm.begin()+l, curPerm.begin()+r+1, curPerm.begin()+p);\n        }\n\n        string Snew = build_S_from_perm(curPerm, bestCapMode, bestRandom);\n        int ec = exact_cost_string(Snew);\n\n        if (ec < curExact) {\n            curExact = ec;\n            if (ec < bestExact) {\n                bestExact = ec;\n                bestPerm = curPerm;\n            }\n        } else {\n            // revert\n            if (type == 0) swap(curPerm[i], curPerm[j]);\n            else if (type == 1) {\n                if (i < j) rotate(curPerm.begin()+i, curPerm.begin()+j,   curPerm.begin()+j+1);\n                else       rotate(curPerm.begin()+j, curPerm.begin()+j+1, curPerm.begin()+i+1);\n            } else {\n                curPerm.swap(backup);\n            }\n        }\n    }\n\n    // Final output\n    string bestS = build_S_from_perm(bestPerm, bestCapMode, bestRandom);\n    auto [finalCost, pathCells] = exact_path_string(bestS);\n    for (int cell : pathCells) {\n        cout << (cell / N) << ' ' << (cell % N) << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    double limit;\n    Timer(double limitSec=2.85) : st(chrono::high_resolution_clock::now()), limit(limitSec) {}\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n    bool over() const { return elapsed() >= limit; }\n};\n\nstruct Query {\n    vector<uint64_t> bits;\n    int k;\n    double y;\n    double w;\n    double base;\n    double alpha;\n    bool exact;\n};\n\nstruct Placement {\n    int di, dj;\n    vector<uint64_t> bits;\n    vector<int16_t> inter;\n    vector<int> neigh;\n};\n\nstruct Field {\n    vector<Placement> ps;\n    int area = 0;\n};\n\nstruct Solution {\n    vector<int> idx;\n    double cost;\n};\n\nstruct Solver {\n    int N, M;\n    double eps;\n    int N2, L;\n    int op_limit;\n    int ops = 0;\n\n    vector<Field> fields;\n    vector<Query> queries;\n    unordered_map<uint64_t, int> qhash2id;\n\n    vector<int> drilledVal;\n    int drilledCnt = 0;\n\n    vector<vector<int>> validList;\n    vector<vector<unsigned char>> validFlag;\n\n    mt19937 rng;\n    Timer timer;\n\n    Solver(int N_, int M_, double eps_) : N(N_), M(M_), eps(eps_), timer(2.85) {\n        N2 = N * N;\n        L = (N2 + 63) / 64;\n        op_limit = 2 * N2;\n        drilledVal.assign(N2, -1);\n        rng.seed((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    }\n\n    // ---- I/O ----\n    void out_flush(const string& s) { cout << s << '\\n' << flush; }\n\n    int drillCell(int i, int j) {\n        out_flush(\"q 1 \" + to_string(i) + \" \" + to_string(j));\n        ops++;\n        int v;\n        if (!(cin >> v)) exit(0);\n        return v;\n    }\n\n    int divineCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        string s;\n        s.reserve(10 + d * 8);\n        s += \"q \" + to_string(d);\n        for (auto &p: ps) s += \" \" + to_string(p.first) + \" \" + to_string(p.second);\n        out_flush(s);\n        ops++;\n        int y;\n        if (!(cin >> y)) exit(0);\n        return y;\n    }\n\n    int answerCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        string s;\n        s.reserve(10 + d * 8);\n        s += \"a \" + to_string(d);\n        for (auto &p: ps) s += \" \" + to_string(p.first) + \" \" + to_string(p.second);\n        out_flush(s);\n        ops++;\n        int ok;\n        if (!(cin >> ok)) exit(0);\n        return ok;\n    }\n\n    bool canSpendOps(int extra) const {\n        int remainingToDrill = N2 - drilledCnt;\n        return ops + extra + remainingToDrill + 1 <= op_limit;\n    }\n\n    // ---- bit helpers ----\n    inline void bitSet(vector<uint64_t>& b, int idx) const { b[idx >> 6] |= 1ULL << (idx & 63); }\n    inline bool bitGet(const vector<uint64_t>& b, int idx) const { return (b[idx >> 6] >> (idx & 63)) & 1ULL; }\n\n    int popcountAnd(const vector<uint64_t>& a, const vector<uint64_t>& b) const {\n        int s = 0;\n        for (int t = 0; t < L; t++) s += __builtin_popcountll(a[t] & b[t]);\n        return s;\n    }\n\n    vector<uint64_t> bitsFromCells(const vector<int>& v) const {\n        vector<uint64_t> b(L, 0ULL);\n        for (int idx: v) bitSet(b, idx);\n        return b;\n    }\n\n    uint64_t hashBits(const vector<uint64_t>& b) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int t = 0; t < (int)b.size(); t++) {\n            h = splitmix64(h ^ splitmix64(b[t] + 0x9e3779b97f4a7c15ULL + (uint64_t)t));\n        }\n        return h;\n    }\n\n    // ---- placements ----\n    void buildPlacements(const vector<vector<pair<int,int>>>& shapes) {\n        fields.resize(M);\n        validList.assign(M, {});\n        validFlag.assign(M, {});\n        for (int f = 0; f < M; f++) {\n            const auto& shp = shapes[f];\n            fields[f].area = (int)shp.size();\n\n            int maxI = 0, maxJ = 0;\n            for (auto [x,y]: shp) { maxI = max(maxI, x); maxJ = max(maxJ, y); }\n            int diMax = N - maxI - 1;\n            int djMax = N - maxJ - 1;\n\n            vector<vector<int>> mp(diMax+1, vector<int>(djMax+1, -1));\n            for (int di = 0; di <= diMax; di++) for (int dj = 0; dj <= djMax; dj++) {\n                Placement p;\n                p.di = di; p.dj = dj;\n                p.bits.assign(L, 0ULL);\n                for (auto [x,y]: shp) {\n                    int i = di + x, j = dj + y;\n                    int idx = i*N + j;\n                    bitSet(p.bits, idx);\n                }\n                fields[f].ps.push_back(std::move(p));\n                mp[di][dj] = (int)fields[f].ps.size()-1;\n            }\n\n            for (auto &p: fields[f].ps) {\n                int di = p.di, dj = p.dj;\n                static int dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n                for (auto &d: dd) {\n                    int ndi = di + d[0], ndj = dj + d[1];\n                    if (0 <= ndi && ndi <= diMax && 0 <= ndj && ndj <= djMax) {\n                        int ni = mp[ndi][ndj];\n                        if (ni >= 0) p.neigh.push_back(ni);\n                    }\n                }\n            }\n\n            int sz = (int)fields[f].ps.size();\n            validList[f].resize(sz);\n            iota(validList[f].begin(), validList[f].end(), 0);\n            validFlag[f].assign(sz, 1);\n        }\n    }\n\n    // ---- queries ----\n    int addOrMergeQuery(const vector<uint64_t>& bits, int k, double y, bool exact) {\n        Query nq;\n        nq.bits = bits;\n        nq.k = k;\n        nq.y = y;\n        nq.exact = exact;\n\n        if (exact) {\n            nq.base = 0.0;\n            nq.alpha = 1.0;\n            nq.w = 1e6;\n        } else {\n            nq.base = (double)k * eps;\n            nq.alpha = 1.0 - 2.0 * eps;\n            double var = (double)k * eps * (1.0 - eps) + 0.25;\n            nq.w = 1.0 / (var + 1e-6);\n        }\n\n        uint64_t h = hashBits(bits);\n        auto it = qhash2id.find(h);\n        if (it != qhash2id.end()) {\n            int id = it->second;\n            Query &q = queries[id];\n            double wsum = q.w + nq.w;\n            q.y = (q.y * q.w + nq.y * nq.w) / wsum;\n            q.w = wsum;\n            q.exact = q.exact || nq.exact;\n            return id;\n        }\n\n        int qid = (int)queries.size();\n        qhash2id[h] = qid;\n        queries.push_back(std::move(nq));\n\n        for (int f = 0; f < M; f++) {\n            for (auto &p: fields[f].ps) {\n                int c = popcountAnd(p.bits, queries[qid].bits);\n                p.inter.push_back((int16_t)c);\n            }\n        }\n        return qid;\n    }\n\n    bool normalizeCells(vector<int>& v) const {\n        for (int x : v) if (x < 0 || x >= N2) return false;\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n        return true;\n    }\n\n    int doDivination(vector<int> cellIdx) {\n        if (!canSpendOps(1)) return -1;\n        if (!normalizeCells(cellIdx)) return -1;\n        if ((int)cellIdx.size() < 2) return -1;\n\n        vector<pair<int,int>> out;\n        out.reserve(cellIdx.size());\n        for (int idx: cellIdx) out.push_back({idx / N, idx % N});\n        int y = divineCells(out);\n\n        auto bits = bitsFromCells(cellIdx);\n        return addOrMergeQuery(bits, (int)cellIdx.size(), (double)y, false);\n    }\n\n    void pruneByZeroCell(int idx) {\n        for (int f = 0; f < M; f++) {\n            vector<int> nv;\n            nv.reserve(validList[f].size());\n            for (int pi : validList[f]) {\n                if (!bitGet(fields[f].ps[pi].bits, idx)) nv.push_back(pi);\n                else validFlag[f][pi] = 0;\n            }\n            if (!nv.empty()) validList[f].swap(nv);\n        }\n    }\n\n    void doDrill(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (!canSpendOps(1)) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<uint64_t> bits(L, 0ULL);\n        bitSet(bits, idx);\n        addOrMergeQuery(bits, 1, (double)v, true);\n\n        if (v == 0) pruneByZeroCell(idx);\n    }\n\n    void doDrillForce(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (ops >= op_limit - 1) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<uint64_t> bits(L, 0ULL);\n        bitSet(bits, idx);\n        addOrMergeQuery(bits, 1, (double)v, true);\n\n        if (v == 0) pruneByZeroCell(idx);\n    }\n\n    // ---- query constructors ----\n    vector<int> allCells() const { vector<int> v(N2); iota(v.begin(), v.end(), 0); return v; }\n    vector<int> cellsRow(int r) const { vector<int> v; v.reserve(N); for(int c=0;c<N;c++) v.push_back(r*N+c); return v; }\n    vector<int> cellsCol(int c) const { vector<int> v; v.reserve(N); for(int r=0;r<N;r++) v.push_back(r*N+c); return v; }\n    vector<int> cellsBlock(int r0,int r1,int c0,int c1) const {\n        vector<int> v;\n        for(int r=r0;r<r1;r++) for(int c=c0;c<c1;c++) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> cellsChecker(int parity) const {\n        vector<int> v;\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++) if(((r+c)&1)==parity) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> randomKCells(int k) {\n        k = max(2, min(k, N2));\n        vector<int> v(N2);\n        iota(v.begin(), v.end(), 0);\n        shuffle(v.begin(), v.end(), rng);\n        v.resize(k);\n        return v;\n    }\n\n    // ---- greedy init ----\n    vector<int> greedyInit() {\n        int Q = (int)queries.size();\n        vector<double> err(Q);\n        for (int q = 0; q < Q; q++) err[q] = queries[q].base - queries[q].y;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){ return fields[a].area > fields[b].area; });\n\n        vector<int> idx(M, 0);\n        for (int f : order) {\n            int bestP = validList[f][0];\n            double bestDelta = 1e100;\n            for (int p : validList[f]) {\n                double delta = 0.0;\n                auto &pl = fields[f].ps[p];\n                for (int q = 0; q < Q; q++) {\n                    int c = (int)pl.inter[q];\n                    if (!c) continue;\n                    double d = queries[q].alpha * (double)c;\n                    delta += queries[q].w * (2.0 * err[q] * d + d * d);\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestP = p;\n                }\n            }\n            idx[f] = bestP;\n            auto &pl = fields[f].ps[bestP];\n            for (int q = 0; q < Q; q++) {\n                int c = (int)pl.inter[q];\n                if (!c) continue;\n                err[q] += queries[q].alpha * (double)c;\n            }\n        }\n        return idx;\n    }\n\n    // ---- SA ----\n    Solution runSA(const vector<int>& startIdx, int iters) {\n        int Q = (int)queries.size();\n        vector<int> idx = startIdx;\n\n        vector<double> err(Q);\n        for (int q = 0; q < Q; q++) err[q] = queries[q].base - queries[q].y;\n        for (int f = 0; f < M; f++) {\n            auto &pl = fields[f].ps[idx[f]];\n            for (int q = 0; q < Q; q++) {\n                int c = (int)pl.inter[q];\n                if (!c) continue;\n                err[q] += queries[q].alpha * (double)c;\n            }\n        }\n        double cost = 0;\n        for (int q = 0; q < Q; q++) cost += queries[q].w * err[q] * err[q];\n\n        vector<int> bestIdx = idx;\n        double bestCost = cost;\n\n        double T0 = 1.15, T1 = 0.03;\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        uniform_int_distribution<int> fieldDist(0, M-1);\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 255) == 0 && timer.over()) break;\n            double tt = (double)it / max(1, iters - 1);\n            double T = T0 * pow(T1 / T0, tt);\n\n            int f = fieldDist(rng);\n            int cur = idx[f];\n            int nxt = cur;\n\n            auto &ps = fields[f].ps;\n            bool proposed = false;\n            if (!ps[cur].neigh.empty() && ur(rng) < 0.70) {\n                uniform_int_distribution<int> nd(0, (int)ps[cur].neigh.size() - 1);\n                int cand = ps[cur].neigh[nd(rng)];\n                if (validFlag[f][cand]) { nxt = cand; proposed = true; }\n            }\n            if (!proposed) {\n                auto &vl = validList[f];\n                uniform_int_distribution<int> vd(0, (int)vl.size() - 1);\n                nxt = vl[vd(rng)];\n            }\n            if (nxt == cur) continue;\n\n            auto &oldP = ps[cur];\n            auto &newP = ps[nxt];\n\n            double delta = 0.0;\n            for (int q = 0; q < Q; q++) {\n                int dd = (int)newP.inter[q] - (int)oldP.inter[q];\n                if (!dd) continue;\n                double d = queries[q].alpha * (double)dd;\n                delta += queries[q].w * (2.0 * err[q] * d + d * d);\n            }\n\n            if (delta <= 0.0 || ur(rng) < exp(-delta / T)) {\n                for (int q = 0; q < Q; q++) {\n                    int dd = (int)newP.inter[q] - (int)oldP.inter[q];\n                    if (!dd) continue;\n                    err[q] += queries[q].alpha * (double)dd;\n                }\n                idx[f] = nxt;\n                cost += delta;\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestIdx = idx;\n                }\n            }\n        }\n        return Solution{bestIdx, bestCost};\n    }\n\n    vector<Solution> sampleSolutions(int wantK, int restarts, int iters) {\n        vector<Solution> sols;\n        sols.reserve(restarts);\n\n        vector<int> base = greedyInit();\n        sols.push_back(runSA(base, iters));\n\n        for (int r = 1; r < restarts; r++) {\n            if (timer.over()) break;\n            vector<int> st = base;\n            for (int t = 0; t < 2; t++) {\n                int f = (int)(rng() % M);\n                auto &vl = validList[f];\n                st[f] = vl[rng() % vl.size()];\n            }\n            sols.push_back(runSA(st, iters));\n        }\n\n        sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b){ return a.cost < b.cost; });\n\n        unordered_set<uint64_t> seen;\n        vector<Solution> out;\n        out.reserve(wantK);\n        for (auto &s: sols) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int x: s.idx) h = splitmix64(h ^ ((uint64_t)x + 0x9e3779b97f4a7c15ULL));\n            if (seen.insert(h).second) out.push_back(s);\n            if ((int)out.size() >= wantK) break;\n        }\n        if (out.empty()) out.push_back(sols[0]);\n        return out;\n    }\n\n    // union bitset for a solution (enforce drills)\n    vector<uint64_t> unionBits(const Solution& s) const {\n        vector<uint64_t> uni(L, 0ULL);\n        for (int f = 0; f < M; f++) {\n            auto &b = fields[f].ps[s.idx[f]].bits;\n            for (int t = 0; t < L; t++) uni[t] |= b[t];\n        }\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] > 0) uni[idx>>6] |= (1ULL << (idx&63));\n            else if (drilledVal[idx] == 0) uni[idx>>6] &= ~(1ULL << (idx&63));\n        }\n        return uni;\n    }\n\n    uint64_t hashUnion(const vector<uint64_t>& uni) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int t = 0; t < L; t++) h = splitmix64(h ^ splitmix64(uni[t] + 0x123456789abcdef0ULL + (uint64_t)t));\n        return h;\n    }\n\n    vector<pair<int,int>> answerFromUnionBits(const vector<uint64_t>& uni) const {\n        vector<pair<int,int>> ans;\n        ans.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) {\n            if ((uni[idx>>6] >> (idx&63)) & 1ULL) ans.push_back({idx / N, idx % N});\n        }\n        return ans;\n    }\n\n    pair<vector<double>, vector<int>> unionProbAndUncertain(const vector<Solution>& sols) const {\n        vector<int> cnt(N2, 0);\n        for (auto &s: sols) {\n            auto uni = unionBits(s);\n            for (int idx = 0; idx < N2; idx++) if ((uni[idx>>6] >> (idx&63)) & 1ULL) cnt[idx]++;\n        }\n        vector<double> p(N2, 0.0);\n        vector<int> uncertain;\n        uncertain.reserve(N2);\n        int K = (int)sols.size();\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] != -1) {\n                p[idx] = (drilledVal[idx] > 0) ? 1.0 : 0.0;\n                continue;\n            }\n            p[idx] = (double)cnt[idx] / max(1, K);\n            if (p[idx] > 0.0 && p[idx] < 1.0) uncertain.push_back(idx);\n        }\n        return {p, uncertain};\n    }\n\n    // choose an informative large mask focusing on a given focus set\n    vector<int> chooseMaskFocus(const vector<int>& focus) {\n        int kTarget = (int)llround((double)N2 * 0.55);\n        kTarget = max(2, min(kTarget, N2));\n        vector<unsigned char> mark(N2, 0);\n        vector<int> mask;\n        mask.reserve(kTarget);\n\n        uniform_real_distribution<double> ur(0.0, 1.0);\n\n        for (int idx : focus) {\n            if ((int)mask.size() >= kTarget) break;\n            if (drilledVal[idx] != -1) continue;\n            if (ur(rng) < 0.65 && !mark[idx]) {\n                mark[idx] = 1;\n                mask.push_back(idx);\n            }\n        }\n        vector<int> all(N2);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n        for (int x : all) {\n            if ((int)mask.size() >= kTarget) break;\n            if (!mark[x]) {\n                mark[x] = 1;\n                mask.push_back(x);\n            }\n        }\n        return mask;\n    }\n\n    void initialDivinations() {\n        doDivination(allCells());\n        for (int i = 0; i < N; i++) doDivination(cellsRow(i));\n        for (int j = 0; j < N; j++) doDivination(cellsCol(j));\n\n        int B = (N >= 18) ? 4 : 3;\n        int step = (N + B - 1) / B;\n        for (int bi = 0; bi < B; bi++) for (int bj = 0; bj < B; bj++) {\n            int r0 = bi * step, r1 = min(N, (bi + 1) * step);\n            int c0 = bj * step, c1 = min(N, (bj + 1) * step);\n            auto v = cellsBlock(r0, r1, c0, c1);\n            if ((int)v.size() >= 2) doDivination(v);\n        }\n\n        doDivination(cellsChecker(0));\n        doDivination(cellsChecker(1));\n\n        int R0 = 65;\n        for (int t = 0; t < R0; t++) {\n            if (!canSpendOps(1)) break;\n            int k = (t & 1) ? (int)llround((double)N2 * 0.50) : (int)llround((double)N2 * 0.62);\n            doDivination(randomKCells(k));\n        }\n    }\n\n    void finalFallbackSolve() {\n        for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] == -1) doDrillForce(idx);\n\n        vector<pair<int,int>> oilCells;\n        oilCells.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n\n        if (ops >= op_limit) return;\n        int ok = answerCells(oilCells);\n        if (ok == 1) return;\n\n        while (ops < op_limit) {\n            bool progressed = false;\n            for (int idx = 0; idx < N2 && ops < op_limit - 1; idx++) {\n                if (drilledVal[idx] == -1) { doDrillForce(idx); progressed = true; }\n            }\n            if (ops >= op_limit) break;\n            oilCells.clear();\n            for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n            int ok2 = answerCells(oilCells);\n            if (ok2 == 1) return;\n            if (!progressed) break;\n        }\n    }\n\n    void solve() {\n        initialDivinations();\n\n        int drillsUsed = 0;\n        int drillBudget = 85;\n        int maxDrillUncertain = 65;\n        int diffDrillThresh = 55;\n\n        int answerAttempts = 0;\n        int maxAnswerAttempts = 7;\n\n        for (int phase = 0; phase < 16; phase++) {\n            if (timer.over()) break;\n\n            int Q = (int)queries.size();\n            int iters = min(10000, 3600 + 10 * Q);\n            int restarts = (eps >= 0.15 ? 22 : 18);\n            int wantK = 60;\n\n            auto sols = sampleSolutions(wantK, restarts, iters);\n            if (sols.empty()) break;\n\n            // cluster by union\n            struct Clu { uint64_t h; int cnt; int rep; double bestCost; int bestSol; };\n            unordered_map<uint64_t, int> id;\n            vector<Clu> clus;\n            clus.reserve(sols.size());\n            vector<vector<uint64_t>> unions;\n            unions.reserve(sols.size());\n\n            for (int i = 0; i < (int)sols.size(); i++) {\n                unions.push_back(unionBits(sols[i]));\n                uint64_t h = hashUnion(unions.back());\n                auto it = id.find(h);\n                if (it == id.end()) {\n                    int nid = (int)clus.size();\n                    id[h] = nid;\n                    clus.push_back(Clu{h, 1, i, sols[i].cost, i});\n                } else {\n                    int cid = it->second;\n                    clus[cid].cnt++;\n                    if (sols[i].cost < clus[cid].bestCost) {\n                        clus[cid].bestCost = sols[i].cost;\n                        clus[cid].bestSol = i;\n                        clus[cid].rep = i;\n                    }\n                }\n            }\n\n            sort(clus.begin(), clus.end(), [](const Clu& a, const Clu& b){\n                if (a.cnt != b.cnt) return a.cnt > b.cnt;\n                return a.bestCost < b.bestCost;\n            });\n\n            auto [p, uncertain] = unionProbAndUncertain(sols);\n\n            // Drill only the disagreement between top two unions if small.\n            vector<int> focus = uncertain;\n            if ((int)clus.size() >= 2) {\n                auto &u1 = unions[clus[0].rep];\n                auto &u2 = unions[clus[1].rep];\n                vector<int> diff;\n                diff.reserve(diffDrillThresh + 10);\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    bool b1 = (u1[idx>>6] >> (idx&63)) & 1ULL;\n                    bool b2 = (u2[idx>>6] >> (idx&63)) & 1ULL;\n                    if (b1 != b2) diff.push_back(idx);\n                }\n                if (!diff.empty() && (int)diff.size() <= diffDrillThresh && drillsUsed + (int)diff.size() <= drillBudget) {\n                    for (int idx : diff) { doDrill(idx); drillsUsed++; }\n                    continue; // re-sample with new exact info\n                }\n                // use diff as focus for next divination if it's smaller than full uncertain\n                if (!diff.empty() && (int)diff.size() < (int)focus.size()) focus = diff;\n            }\n\n            // Majority union attempt (more aggressive, multiple tries are cheap)\n            if (answerAttempts < maxAnswerAttempts && canSpendOps(1)) {\n                double dom = (double)clus[0].cnt / (double)max(1, (int)sols.size());\n                double domThr = (eps <= 0.06 ? 0.58 : eps <= 0.12 ? 0.65 : 0.70);\n                if (dom >= domThr) {\n                    auto ans = answerFromUnionBits(unions[clus[0].rep]);\n                    int ok = answerCells(ans);\n                    answerAttempts++;\n                    if (ok == 1) return;\n                    // wrong -> add one focused divination to break ambiguity\n                    if (canSpendOps(1)) doDivination(chooseMaskFocus(focus));\n                    continue;\n                }\n            }\n\n            // Drill all uncertain if moderate\n            if ((int)uncertain.size() <= maxDrillUncertain &&\n                drillsUsed + (int)uncertain.size() <= drillBudget) {\n                for (int idx : uncertain) { doDrill(idx); drillsUsed++; }\n                continue;\n            }\n\n            // Pruning drill: low union probability cells (expect 0)\n            if (drillsUsed < drillBudget && canSpendOps(1) && phase >= 2) {\n                vector<pair<double,int>> cand;\n                cand.reserve(N2);\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    double pu = p[idx];\n                    if (pu > 0.01 && pu < 0.16) cand.push_back({pu, idx});\n                }\n                sort(cand.begin(), cand.end());\n                int take = min(2, (int)cand.size());\n                for (int t = 0; t < take && drillsUsed < drillBudget; t++) {\n                    doDrill(cand[t].second);\n                    drillsUsed++;\n                }\n            }\n\n            // Add 1\u20132 focused divinations when still very uncertain\n            if (canSpendOps(1)) {\n                doDivination(chooseMaskFocus(focus));\n                if ((int)uncertain.size() > 140 && canSpendOps(1)) {\n                    doDivination(chooseMaskFocus(focus));\n                }\n            } else break;\n        }\n\n        finalFallbackSolve();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    double eps;\n    cin >> N >> M >> eps;\n\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; k++) {\n        int d; cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; t++) {\n            int i, j; cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    Solver solver(N, M, eps);\n    solver.buildPlacements(shapes);\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF = (1LL<<60);\n\nstruct XorShift {\n    uint64_t x=88172645463325252ULL;\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n};\n\nstatic inline void build_in(const vector<int>& h, bitset<W+1>& in, vector<int>& pref) {\n    int N = (int)h.size();\n    pref.assign(N+1, 0);\n    for(int i=0;i<N;i++) pref[i+1] = pref[i] + h[i];\n    in.reset();\n    for(int b=1;b<=N-1;b++){\n        int y = pref[b];\n        if(1 <= y && y <= W-1) in.set(y);\n    }\n}\n\nstatic vector<int> dp_feasible_setbased(const vector<int>& need,\n                                       const bitset<W+1>* prevIn,\n                                       const bitset<W+1>* nextIn,\n                                       const vector<int>& curPref) {\n    int N = (int)need.size();\n    vector<int> suf(N+1, 0);\n    for(int i=N-1;i>=0;i--) suf[i] = suf[i+1] + need[i];\n\n    static long long dp[W+1], ndp[W+1], bestVal[W+1];\n    static int bestIdx[W+1];\n    static int16_t par[55][W+1]; // N<=50\n    for(int p=0;p<=W;p++) dp[p] = -INF;\n    dp[0] = 0;\n    for(int k=0;k<=N;k++) for(int p=0;p<=W;p++) par[k][p] = -1;\n\n    auto w_at = [&](int y)->int{\n        int w = 0;\n        if(prevIn && prevIn->test(y)) w++;\n        if(nextIn && nextIn->test(y)) w++;\n        return w;\n    };\n\n    for(int k=0;k<N;k++){\n        bestVal[0] = dp[0];\n        bestIdx[0] = 0;\n        for(int p=1;p<=W;p++){\n            if(dp[p] > bestVal[p-1]){\n                bestVal[p] = dp[p];\n                bestIdx[p] = p;\n            }else{\n                bestVal[p] = bestVal[p-1];\n                bestIdx[p] = bestIdx[p-1];\n            }\n        }\n\n        for(int p=0;p<=W;p++) ndp[p] = -INF;\n\n        for(int p2=0;p2<=W;p2++){\n            if(W - p2 < suf[k+1]) continue;\n            int lim = p2 - need[k];\n            if(lim < 0) continue;\n            long long base = bestVal[lim];\n            if(base <= -INF/4) continue;\n\n            long long add = 0;\n            if(k < N-1){\n                int ww = w_at(p2);\n                add += 2000LL * ww;                 // exact match benefit\n                int bidx = k+1;\n                if(bidx < (int)curPref.size()) add -= llabs((long long)p2 - curPref[bidx]); // tiny tie-break\n            }\n            long long val = base + add;\n\n            if(val > ndp[p2]){\n                ndp[p2] = val;\n                par[k+1][p2] = (int16_t)bestIdx[lim];\n            }\n        }\n        for(int p=0;p<=W;p++) dp[p] = ndp[p];\n    }\n\n    int p = W;\n    if(dp[p] <= -INF/4){\n        vector<int> h = need;\n        int s = accumulate(h.begin(), h.end(), 0);\n        h.back() += (W - s);\n        return h;\n    }\n\n    vector<int> h(N, 1);\n    for(int k=N-1;k>=0;k--){\n        int pPrev = par[k+1][p];\n        if(pPrev < 0) pPrev = max(0, p - need[k]);\n        h[k] = p - pPrev;\n        p = pPrev;\n    }\n    int sumH = accumulate(h.begin(), h.end(), 0);\n    h.back() += (W - sumH);\n    if(h.back() <= 0) h.back() = 1;\n    return h;\n}\n\n// Optimize permutation of heights by random restarts + greedy adjacent swaps\nstatic vector<int> perm_optimize_adjacent(const vector<int>& base,\n                                         const bitset<W+1>* prevIn,\n                                         const bitset<W+1>* nextIn,\n                                         int restarts,\n                                         XorShift& rng) {\n    int N = (int)base.size();\n\n    auto w_at = [&](int y)->int{\n        int w = 0;\n        if(prevIn && prevIn->test(y)) w++;\n        if(nextIn && nextIn->test(y)) w++;\n        return w;\n    };\n\n    auto score_of = [&](const vector<int>& h)->int{\n        int s = 0, y = 0;\n        for(int i=0;i<N-1;i++){\n            y += h[i];\n            if(1 <= y && y <= W-1) s += w_at(y);\n        }\n        return s;\n    };\n\n    auto hillclimb = [&](vector<int> h)->pair<vector<int>, int>{\n        vector<int> pref(N+1, 0);\n        for(int i=0;i<N;i++) pref[i+1] = pref[i] + h[i];\n\n        int sc = 0;\n        for(int b=1;b<=N-1;b++){\n            int y = pref[b];\n            if(1 <= y && y <= W-1) sc += w_at(y);\n        }\n\n        bool improved = true;\n        while(improved){\n            improved = false;\n            for(int i=0;i<N-1;i++){\n                int q_old = pref[i+1];\n                int q_new = pref[i] + h[i+1];\n                if(q_old == q_new) continue;\n                int delta = w_at(q_new) - w_at(q_old);\n                if(delta > 0){\n                    swap(h[i], h[i+1]);\n                    pref[i+1] = q_new; // only this boundary changes; later pref unchanged\n                    sc += delta;\n                    improved = true;\n                }\n            }\n        }\n        return {h, sc};\n    };\n\n    vector<int> best = base;\n    int bestScore = score_of(best);\n\n    // Deterministic additional starts\n    {\n        auto [h1,s1] = hillclimb(best);\n        if(s1 > bestScore){ bestScore = s1; best = h1; }\n        vector<int> asc = base; sort(asc.begin(), asc.end());\n        auto [h2,s2] = hillclimb(asc);\n        if(s2 > bestScore){ bestScore = s2; best = h2; }\n        vector<int> desc = asc; reverse(desc.begin(), desc.end());\n        auto [h3,s3] = hillclimb(desc);\n        if(s3 > bestScore){ bestScore = s3; best = h3; }\n    }\n\n    // Random restarts\n    for(int r=0;r<restarts;r++){\n        vector<int> cand = base;\n        // Fisher\u2013Yates shuffle\n        for(int i=N-1;i>=1;i--){\n            int j = rng.next_int(i+1);\n            swap(cand[i], cand[j]);\n        }\n        auto [hc, sc] = hillclimb(cand);\n        if(sc > bestScore){\n            bestScore = sc;\n            best = std::move(hc);\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Win, D, N;\n    cin >> Win >> D >> N;\n    (void)Win;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for(int d=0; d<D; d++) for(int k=0; k<N; k++) cin >> a[d][k];\n\n    vector<vector<int>> need(D, vector<int>(N));\n    vector<int> sumNeed(D, 0);\n    for(int d=0; d<D; d++){\n        int s=0;\n        for(int k=0;k<N;k++){\n            need[d][k] = max(1, (a[d][k] + W - 1)/W);\n            s += need[d][k];\n        }\n        sumNeed[d] = s;\n    }\n\n    vector<vector<int>> h(D, vector<int>(N,1));\n    for(int d=0; d<D; d++){\n        if(sumNeed[d] <= W){\n            h[d] = need[d];\n            h[d].back() += (W - sumNeed[d]);\n        }else{\n            // Simple penalty-minimizing multiset (keep as sorted physical order)\n            // (same as earlier good solutions)\n            vector<int> hh = need[d];\n            int T = sumNeed[d] - W;\n\n            vector<int> firstCost(N);\n            for(int k=0;k<N;k++){\n                int r = a[d][k] % W;\n                int deltaArea = (r == 0 ? W : r);\n                firstCost[k] = 100 * deltaArea;\n            }\n            using P = pair<int,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            for(int k=0;k<N;k++) if(hh[k] > 1) pq.push({firstCost[k], k});\n            for(int t=0;t<T;t++){\n                auto [c,k] = pq.top(); pq.pop();\n                hh[k]--;\n                if(hh[k] > 1) pq.push({100000, k});\n            }\n            sort(hh.begin(), hh.end());\n            int sumH = accumulate(hh.begin(), hh.end(), 0);\n            hh.back() += (W - sumH);\n            sort(hh.begin(), hh.end());\n            h[d] = hh;\n        }\n        int s = accumulate(h[d].begin(), h[d].end(), 0);\n        h[d].back() += (W - s);\n    }\n\n    vector<bitset<W+1>> in(D);\n    vector<vector<int>> pref(D);\n    for(int d=0; d<D; d++) build_in(h[d], in[d], pref[d]);\n\n    XorShift rng;\n\n    // Coordinate descent: DP (feasible days) + randomized permutation optimization (all days)\n    const int ITER = 6;\n    for(int it=0; it<ITER; it++){\n        for(int d=0; d<D; d++){\n            const bitset<W+1>* pPrev = (d>0 ? &in[d-1] : nullptr);\n            const bitset<W+1>* pNext = (d+1<D ? &in[d+1] : nullptr);\n\n            if(sumNeed[d] <= W){\n                vector<int> curPref = pref[d];\n                vector<int> base = dp_feasible_setbased(need[d], pPrev, pNext, curPref);\n                int s = accumulate(base.begin(), base.end(), 0);\n                base.back() += (W - s);\n\n                // Add randomized within-day order search (keeps multiset => still zero shortage)\n                // Use more restarts for mid days where both neighbors exist.\n                int restarts = (pPrev && pNext) ? 10 : 6;\n                base = perm_optimize_adjacent(base, pPrev, pNext, restarts, rng);\n\n                h[d] = std::move(base);\n                build_in(h[d], in[d], pref[d]);\n            }else{\n                // infeasible: keep multiset fixed, only optimize order (does not change penalty)\n                int restarts = (pPrev && pNext) ? 10 : 6;\n                vector<int> base = perm_optimize_adjacent(h[d], pPrev, pNext, restarts, rng);\n                h[d] = std::move(base);\n                build_in(h[d], in[d], pref[d]);\n            }\n        }\n    }\n\n    // Output: build physical stripes; assign reservations by sorting stripe heights (optimal for shortage).\n    for(int d=0; d<D; d++){\n        vector<array<int,4>> stripeRect(N);\n        int y=0;\n        for(int s=0; s<N; s++){\n            int y2 = y + h[d][s];\n            if(s == N-1) y2 = W;\n            stripeRect[s] = {y, 0, y2, W};\n            y = y2;\n        }\n\n        vector<int> idx(N);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int i, int j){\n            return h[d][i] < h[d][j];\n        });\n\n        for(int k=0; k<N; k++){\n            auto r = stripeRect[idx[k]];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << \"\\n\";\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline uint32_t addmod(uint32_t a, uint32_t b) {\n    uint32_t s = a + b;\n    if (s >= MOD) s -= MOD;\n    return s;\n}\nstatic inline uint32_t negmod(uint32_t a) {\n    return a ? (MOD - a) : 0u;\n}\n\nstruct Action {\n    uint8_t m, p, q;\n    uint8_t idx[9];   // affected cell indices 0..80\n    uint32_t val[9];  // added values mod MOD\n};\n\nstruct DeltaBuf {\n    array<uint32_t, 81> delta{};\n    array<int, 81> vis{};\n    int iter = 1;\n    uint8_t cells[18];\n    int cnt = 0;\n\n    inline void clear() {\n        iter++;\n        if (iter == INT_MAX) { // very unlikely, but safe\n            iter = 1;\n            vis.fill(0);\n        }\n        cnt = 0;\n    }\n    inline void addCell(uint8_t c, uint32_t dv) {\n        if (dv == 0) return;\n        if (vis[c] != iter) {\n            vis[c] = iter;\n            delta[c] = dv;\n            cells[cnt++] = c;\n        } else {\n            delta[c] = addmod(delta[c], dv);\n        }\n    }\n};\n\nstatic inline int64_t add_gain_only(const Action &a, const array<uint32_t,81> &res) {\n    int64_t d = 0;\n    for (int k = 0; k < 9; k++) {\n        uint8_t c = a.idx[k];\n        uint32_t r = res[c];\n        uint32_t nr = r + a.val[k];\n        if (nr >= MOD) nr -= MOD;\n        d += (int64_t)nr - (int64_t)r;\n    }\n    return d;\n}\n\nstatic inline int64_t compute_change(int oldId, int newId,\n                                    const vector<Action> &actions,\n                                    const array<uint32_t,81> &res,\n                                    DeltaBuf &buf) {\n    buf.clear();\n    if (oldId != -1) {\n        const auto &a = actions[oldId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], negmod(a.val[k]));\n    }\n    if (newId != -1) {\n        const auto &a = actions[newId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], a.val[k]);\n    }\n    int64_t dscore = 0;\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        dscore += (int64_t)nr - (int64_t)r;\n    }\n    return dscore;\n}\n\nstatic inline void apply_change(const DeltaBuf &buf, array<uint32_t,81> &res) {\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        res[c] = nr;\n    }\n}\n\nstatic inline int64_t score_of(const array<uint32_t,81> &res) {\n    int64_t s = 0;\n    for (uint32_t v : res) s += v;\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K; // N=9,M=20,K=81\n\n    array<uint32_t,81> a0{};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        uint64_t x; cin >> x;\n        a0[i*N + j] = (uint32_t)(x % MOD);\n    }\n\n    vector<array<uint32_t,9>> stamps(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n            uint64_t x; cin >> x;\n            stamps[m][i*3 + j] = (uint32_t)(x % MOD);\n        }\n    }\n\n    // Precompute actions\n    vector<Action> actions;\n    actions.reserve(M * (N-2) * (N-2));\n    // mapping: stamp m, pos (p*7+q) -> action id\n    array<array<int, 49>, 20> idOf{};\n    for (int m = 0; m < M; m++) for (int pos = 0; pos < 49; pos++) idOf[m][pos] = -1;\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action act;\n                act.m = (uint8_t)m;\n                act.p = (uint8_t)p;\n                act.q = (uint8_t)q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n                    int bi = p + i, bj = q + j;\n                    act.idx[t] = (uint8_t)(bi * N + bj);\n                    act.val[t] = stamps[m][i*3 + j];\n                    t++;\n                }\n                int id = (int)actions.size();\n                actions.push_back(act);\n                int pos = p * 7 + q;\n                idOf[m][pos] = id;\n            }\n        }\n    }\n    const int A = (int)actions.size(); // 980\n\n    // Seed RNG input-dependent\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 81; i++) seed = seed * 1000003ULL + a0[i];\n    XorShift64 rng(seed);\n\n    // exp lookup for x in [-20,0]\n    static vector<double> expTab;\n    if (expTab.empty()) {\n        const int STEPS = 8192;\n        expTab.resize(STEPS + 1);\n        for (int i = 0; i <= STEPS; i++) {\n            double x = -20.0 * (double)i / (double)STEPS;\n            expTab[i] = exp(x);\n        }\n    }\n    auto exp_lookup = [&](double x)->double { // x in [-20,0]\n        if (x <= -20.0) return 0.0;\n        if (x >= 0.0) return 1.0;\n        const int STEPS = (int)expTab.size() - 1;\n        int idx = (int)llround((-x) * (double)STEPS / 20.0);\n        if (idx < 0) idx = 0;\n        if (idx > STEPS) idx = STEPS;\n        return expTab[idx];\n    };\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n\n    auto elapsedSec = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    auto best_stamp_for_pos = [&](int pos, const array<uint32_t,81> &res)->int {\n        int bestId = -1;\n        int64_t bestGain = LLONG_MIN;\n        for (int m = 0; m < M; m++) {\n            int id = idOf[m][pos];\n            int64_t g = add_gain_only(actions[id], res);\n            if (g > bestGain) {\n                bestGain = g;\n                bestId = id;\n            }\n        }\n        return bestId;\n    };\n\n    // Build solution from ops\n    auto rebuild = [&](const vector<int> &ops, array<uint32_t,81> &res)->int64_t {\n        res = a0;\n        for (int id : ops) {\n            if (id == -1) continue;\n            const auto &a = actions[id];\n            for (int k = 0; k < 9; k++) {\n                uint8_t c = a.idx[k];\n                uint32_t nr = res[c] + a.val[k];\n                if (nr >= MOD) nr -= MOD;\n                res[c] = nr;\n            }\n        }\n        return score_of(res);\n    };\n\n    // One run: init then SA+LNS, return best\n    vector<int> globalBestOps(K, -1);\n    int64_t globalBestScore = score_of(a0);\n\n    DeltaBuf buf;\n\n    auto do_run = [&](int mode, double endTimeSec) {\n        // mode 0: greedy with small randomness\n        // mode 1: randomized by position (choose pos random, best stamp for that pos wrt current)\n        vector<int> ops(K, -1);\n        array<uint32_t,81> res = a0;\n        int64_t score = score_of(res);\n\n        if (mode == 0) {\n            // Greedy fill, but sometimes pick among top few to diversify\n            for (int slot = 0; slot < K; slot++) {\n                int best1 = -1, best2 = -1, best3 = -1;\n                int64_t g1 = 0, g2 = 0, g3 = 0;\n                for (int id = 0; id < A; id++) {\n                    int64_t g = add_gain_only(actions[id], res);\n                    if (g > g1) {\n                        best3 = best2; g3 = g2;\n                        best2 = best1; g2 = g1;\n                        best1 = id;    g1 = g;\n                    } else if (g > g2) {\n                        best3 = best2; g3 = g2;\n                        best2 = id;    g2 = g;\n                    } else if (g > g3) {\n                        best3 = id;    g3 = g;\n                    }\n                }\n                if (best1 == -1 || g1 <= 0) break;\n                int pick = best1;\n                // 15%: pick best2/3 if close\n                if (rng.nextInt(100) < 15) {\n                    int r = rng.nextInt(3);\n                    if (r == 1 && best2 != -1) pick = best2;\n                    if (r == 2 && best3 != -1) pick = best3;\n                }\n                ops[slot] = pick;\n                const auto &a = actions[pick];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n                score += add_gain_only(a, res); // WRONG if used after applying; avoid; keep score by recomputing delta before apply\n                // Fix: we won't use this broken score update; recompute after greedy loop.\n                // (We keep this line harmless by overwriting score below.)\n            }\n            score = score_of(res);\n        } else {\n            // Randomized position-based construction\n            for (int slot = 0; slot < K; slot++) {\n                int pos = rng.nextInt(49);\n                int id = best_stamp_for_pos(pos, res);\n                // small chance to take random stamp instead\n                if (rng.nextInt(100) < 10) {\n                    int m = rng.nextInt(M);\n                    id = idOf[m][pos];\n                }\n                ops[slot] = id;\n                const auto &a = actions[id];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n            }\n            score = score_of(res);\n        }\n\n        // track local best\n        vector<int> bestOps = ops;\n        int64_t bestScore = score;\n        array<uint32_t,81> bestRes = res;\n\n        // SA parameters\n        const double T0 = 2.0e9;\n        const double T1 = 2.0e6;\n        const double logRatio = log(T1 / T0);\n\n        double lastCheck = elapsedSec();\n        double T = T0;\n        uint64_t iters = 0;\n\n        auto accept_move = [&](int64_t d)->bool {\n            if (d >= 0) return true;\n            double x = (double)d / T; // negative\n            double prob = exp_lookup(x);\n            return rng.nextDouble() < prob;\n        };\n\n        // SA loop\n        while (true) {\n            iters++;\n\n            if ((iters & 2047ull) == 0) {\n                double e = elapsedSec();\n                if (e >= endTimeSec) break;\n                double prog = (e - lastCheck) / max(1e-9, (endTimeSec - lastCheck)); // not great; use global progress instead\n                (void)prog;\n                double globalProg = min(1.0, e / endTimeSec);\n                T = T0 * exp(logRatio * globalProg);\n            }\n\n            int moveType = rng.nextInt(100);\n            if (moveType < 70) {\n                // 1-slot replace\n                int slot = rng.nextInt(K);\n                int oldId = ops[slot];\n\n                int newId = -1;\n                int r = rng.nextInt(100);\n\n                if (r < 10) {\n                    newId = -1;\n                } else if (r < 40) {\n                    // random action\n                    newId = rng.nextInt(A);\n                } else if (r < 65) {\n                    // best stamp for random pos\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1 && r < 85) {\n                    // same position, best stamp\n                    int pos = actions[oldId].p * 7 + actions[oldId].q;\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1) {\n                    // same stamp, random position\n                    int m = actions[oldId].m;\n                    int pos = rng.nextInt(49);\n                    newId = idOf[m][pos];\n                } else {\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                }\n\n                if (newId == oldId) continue;\n\n                int64_t d = compute_change(oldId, newId, actions, res, buf);\n                if (accept_move(d)) {\n                    apply_change(buf, res);\n                    score += d;\n                    ops[slot] = newId;\n\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else if (moveType < 90) {\n                // 2-slot replace\n                int s1 = rng.nextInt(K);\n                int s2 = rng.nextInt(K);\n                if (s1 == s2) continue;\n                int old1 = ops[s1], old2 = ops[s2];\n\n                int new1, new2;\n                // propose using strong candidates sometimes\n                auto propose = [&](int oldId)->int {\n                    int rr = rng.nextInt(100);\n                    if (rr < 10) return -1;\n                    if (rr < 35) return rng.nextInt(A);\n                    if (rr < 70) {\n                        int pos = rng.nextInt(49);\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    if (oldId != -1) {\n                        int pos = actions[oldId].p * 7 + actions[oldId].q;\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    int pos = rng.nextInt(49);\n                    return best_stamp_for_pos(pos, res);\n                };\n                new1 = propose(old1);\n                new2 = propose(old2);\n                if (new1 == old1 && new2 == old2) continue;\n\n                // apply combined by sequential compute in a temp copy (cheap, 81 cells)\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // change slot1\n                int64_t d1 = compute_change(old1, new1, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d1;\n                // change slot2 (note: use updated tmpRes)\n                int64_t d2 = compute_change(old2, new2, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d2;\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    res = tmpRes;\n                    score = tmpScore;\n                    ops[s1] = new1;\n                    ops[s2] = new2;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else {\n                // LNS: remove t random slots, then greedily refill\n                int t = 6 + rng.nextInt(7); // 6..12\n                vector<int> idx(K);\n                iota(idx.begin(), idx.end(), 0);\n                for (int i = 0; i < t; i++) {\n                    int j = i + rng.nextInt(K - i);\n                    swap(idx[i], idx[j]);\n                }\n                idx.resize(t);\n\n                vector<int> tmpOps = ops;\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // remove chosen slots\n                for (int slot : idx) {\n                    int oldId = tmpOps[slot];\n                    if (oldId == -1) continue;\n                    int64_t d = compute_change(oldId, -1, actions, tmpRes, buf);\n                    apply_change(buf, tmpRes);\n                    tmpScore += d;\n                    tmpOps[slot] = -1;\n                }\n\n                // greedy refill chosen slots (leave empty if bestGain <= 0 most of the time)\n                for (int slot : idx) {\n                    int bestId = -1;\n                    int64_t bestG = LLONG_MIN;\n\n                    // Use a mix: try best over all actions, but we can speed by also trying best-per-pos sometimes.\n                    // Since A=980 small, full scan is fine here.\n                    for (int id = 0; id < A; id++) {\n                        int64_t g = add_gain_only(actions[id], tmpRes);\n                        if (g > bestG) { bestG = g; bestId = id; }\n                    }\n\n                    if (bestId != -1) {\n                        bool take = (bestG > 0) || (rng.nextInt(100) < 10); // 10% take even if <=0\n                        if (take) {\n                            const auto &a = actions[bestId];\n                            for (int k = 0; k < 9; k++) {\n                                uint8_t c = a.idx[k];\n                                uint32_t nr = tmpRes[c] + a.val[k];\n                                if (nr >= MOD) nr -= MOD;\n                                tmpRes[c] = nr;\n                            }\n                            tmpOps[slot] = bestId;\n                            // update tmpScore by exact delta\n                            // (use add_gain_only on original res would be wrong; recompute via direct diff)\n                            // easiest: recompute score delta for 9 cells:\n                            // but we already updated tmpRes; so compute delta by subtracting old via storing old values:\n                            // keep it simple: compute after all refills (81 cells only).\n                        }\n                    }\n                }\n                tmpScore = score_of(tmpRes);\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    ops.swap(tmpOps);\n                    res = tmpRes;\n                    score = tmpScore;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            }\n        }\n\n        // Final local refinement: repeat 1-opt until no improvement or time\n        ops = bestOps;\n        score = rebuild(ops, res);\n        bool any = true;\n        while (any && elapsedSec() < endTimeSec) {\n            any = false;\n            vector<int> order(K);\n            iota(order.begin(), order.end(), 0);\n            // lightweight shuffle\n            for (int i = 0; i < K; i++) swap(order[i], order[rng.nextInt(K)]);\n\n            for (int t = 0; t < K; t++) {\n                if (elapsedSec() >= endTimeSec) break;\n                int slot = order[t];\n                int oldId = ops[slot];\n\n                int bestNew = oldId;\n                int64_t bestD = 0;\n                DeltaBuf bestBufLocal;\n\n                // try empty\n                {\n                    int64_t d = compute_change(oldId, -1, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = -1;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                // try all actions\n                for (int id = 0; id < A; id++) {\n                    if (id == oldId) continue;\n                    int64_t d = compute_change(oldId, id, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = id;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                if (bestNew != oldId) {\n                    apply_change(bestBufLocal, res);\n                    score += bestD;\n                    ops[slot] = bestNew;\n                    any = true;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                    }\n                }\n            }\n        }\n\n        if (bestScore > globalBestScore) {\n            globalBestScore = bestScore;\n            globalBestOps = bestOps;\n        }\n    };\n\n    // Time budgeting: 2 runs + final polishing built-in each run\n    // Run 1: greedy-ish init\n    do_run(0, min(TL, 1.30));\n    // Run 2: randomized init, use remaining time\n    do_run(1, TL);\n\n    // Output\n    vector<tuple<int,int,int>> out;\n    out.reserve(K);\n    for (int id : globalBestOps) {\n        if (id == -1) continue;\n        const auto &a = actions[id];\n        out.emplace_back((int)a.m, (int)a.p, (int)a.q);\n    }\n    cout << out.size() << \"\\n\";\n    for (auto &[m,p,q] : out) {\n        cout << m << \" \" << p << \" \" << q << \"\\n\";\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 5;\nstatic const int MAX_TURNS = 10000;\n\nstruct Solver {\n    int A[N][N];\n    int origRow[N*N], origIdx[N*N];\n\n    // grid container id or -1\n    int grid[N][N];\n\n    // position of each container if on grid else (-1,-1)\n    int posR[N*N], posC[N*N];\n\n    // receiving progress\n    int spawned[N];\n\n    // dispatch progress: bit k means (rowGroup*5 + k) has been dispatched\n    int dispMask[N];\n    int dispatchedCount = 0;\n\n    struct Crane {\n        int r=0, c=0;\n        bool alive=true;\n        bool holding=false;\n        int held=-1;\n        bool large=false;\n    };\n    Crane cranes[N]; // 0 large, 1..4 small\n\n    deque<char> plan0;\n    vector<string> out;\n    int turn = 0;\n\n    // progress / safety\n    int lastDispatchedCount = 0;\n    int noDispatchTurns = 0;\n    bool panic = false;\n\n    // Tunables\n    static constexpr int STUCK_LIMIT = 450;    // if no dispatch for this many turns -> panic\n    static constexpr int LATE_LIMIT  = 8500;   // force panic if not done by this time\n\n    Solver(const vector<vector<int>>& Ain) : out(N, \"\") {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            A[i][j] = Ain[i][j];\n            origRow[A[i][j]] = i;\n            origIdx[A[i][j]] = j;\n        }\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) grid[i][j] = -1;\n        for(int id=0;id<N*N;id++) posR[id] = posC[id] = -1;\n        for(int i=0;i<N;i++){\n            spawned[i] = 0;\n            dispMask[i] = 0;\n        }\n        for(int i=0;i<N;i++){\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].alive = true;\n            cranes[i].holding = false;\n            cranes[i].held = -1;\n            cranes[i].large = (i==0);\n        }\n    }\n\n    // ===== dispatch helpers =====\n    int expectedIndex(int t) const {\n        for(int k=0;k<N;k++){\n            if(((dispMask[t] >> k) & 1) == 0) return k;\n        }\n        return N;\n    }\n    int expectedId(int t) const {\n        int k = expectedIndex(t);\n        if(k>=N) return -1;\n        return N*t + k;\n    }\n    int invCostIfDispatch(int id) const {\n        int t = id / N;\n        int idx = id % N;\n        int cost = 0;\n        for(int k=0;k<idx;k++){\n            if(((dispMask[t] >> k) & 1) == 0) cost++;\n        }\n        return cost;\n    }\n\n    // ===== crane helpers =====\n    bool craneAtCell(int r,int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n    bool holdingCraneAtCell(int r,int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].holding && cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n\n    // ===== spawn phase =====\n    void spawnPhase(){\n        for(int r=0;r<N;r++){\n            if(spawned[r] >= N) continue;\n            if(grid[r][0] != -1) continue;\n            if(holdingCraneAtCell(r,0)) continue;\n            int id = A[r][spawned[r]++];\n            grid[r][0] = id;\n            posR[id] = r;\n            posC[id] = 0;\n        }\n    }\n\n    // ===== storage cells =====\n    // Normal mode: reserve (i,1) for i>0 as buffer, and avoid active gates (i,0) while spawned[i]<N.\n    // Panic: allow anything except dispatch column, but still avoid cells occupied by other cranes.\n    bool isAllowedStorageCell(int r,int c) const {\n        if(c == 4) return false;\n        if(grid[r][c] != -1) return false;\n        // can't place into a cell with any crane (we could place under our own crane, but storage targets are where we'll move)\n        if(craneAtCell(r,c)) return false;\n\n        if(!panic){\n            if(r > 0 && c == 1) return false;          // buffer reserved\n            if(c == 0 && spawned[r] < N) return false; // active receiving gate\n        }\n        return true;\n    }\n\n    int countEmptyStorageCells() const {\n        int cnt=0;\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++){\n            if(isAllowedStorageCell(r,c)) cnt++;\n        }\n        return cnt;\n    }\n\n    pair<int,int> chooseStorageCellFor(int id, int fromR, int fromC) const {\n        int t = id / N;\n        // prefer near destination row and right side\n        vector<pair<int,int>> pref = {\n            {t,3},{t,2},{t,1},{0,3},{0,2},{0,1},{t,0},{0,0}\n        };\n        for(auto [r,c]: pref){\n            if(isAllowedStorageCell(r,c)) return {r,c};\n        }\n        int bestD = INT_MAX;\n        pair<int,int> best = {-1,-1};\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++){\n            if(!isAllowedStorageCell(r,c)) continue;\n            int d = abs(fromR-r) + abs(fromC-c);\n            if(r==t) d -= 1;\n            if(d < bestD){\n                bestD = d;\n                best = {r,c};\n            }\n        }\n        return best;\n    }\n\n    // ===== large crane movement restrictions (to avoid collisions) =====\n    bool forbiddenForLarge(int r,int c,int tr,int tc) const {\n        if(panic) return false;\n        if(r > 0 && c == 0) return true; // never enter small-crane gate cells\n        if(r > 0 && c == 1 && !(r==tr && c==tc)) return true; // don't pass through buffers\n        return false;\n    }\n\n    vector<char> bfsPathLarge(int sr,int sc,int tr,int tc) const {\n        if(sr==tr && sc==tc) return {};\n\n        // cannot move into a cell currently occupied by another crane\n        for(int k=1;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==tr && cranes[k].c==tc) return {};\n        }\n\n        array<array<int,N>,N> dist;\n        array<array<pair<int,int>,N>,N> prev;\n        array<array<char,N>,N> pm;\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            dist[i][j] = -1;\n            prev[i][j] = {-1,-1};\n            pm[i][j] = '?';\n        }\n\n        auto blocked = [&](int r,int c)->bool{\n            if(r<0||r>=N||c<0||c>=N) return true;\n            if(forbiddenForLarge(r,c,tr,tc)) return true;\n            for(int k=1;k<N;k++){\n                if(!cranes[k].alive) continue;\n                if(cranes[k].r==r && cranes[k].c==c) return true;\n            }\n            return false;\n        };\n\n        queue<pair<int,int>> q;\n        dist[sr][sc] = 0;\n        q.push({sr,sc});\n        const int dr[4] = {-1,1,0,0};\n        const int dc[4] = {0,0,-1,1};\n        const char mv[4] = {'U','D','L','R'};\n\n        while(!q.empty()){\n            auto [r,c] = q.front(); q.pop();\n            for(int k=0;k<4;k++){\n                int nr=r+dr[k], nc=c+dc[k];\n                if(blocked(nr,nc)) continue;\n                if(dist[nr][nc]!=-1) continue;\n                dist[nr][nc] = dist[r][c] + 1;\n                prev[nr][nc] = {r,c};\n                pm[nr][nc] = mv[k];\n                q.push({nr,nc});\n            }\n        }\n        if(dist[tr][tc] == -1) return {};\n\n        vector<char> path;\n        int r=tr,c=tc;\n        while(!(r==sr && c==sc)){\n            path.push_back(pm[r][c]);\n            auto p = prev[r][c];\n            r = p.first; c = p.second;\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    int estDistLarge(int sr,int sc,int tr,int tc) const {\n        if(sr==tr && sc==tc) return 0;\n        auto p = bfsPathLarge(sr,sc,tr,tc);\n        if(p.empty()) return 1e9;\n        return (int)p.size();\n    }\n\n    // ===== small crane policy =====\n    // Normal: shuttle gate->buffer (cols 0-1). Never bomb.\n    char decideSmallNormal(int i, int lockRow) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n        if(lockRow==i) return '.';\n\n        int r=cr.r, c=cr.c;\n        if(cr.holding){\n            if(c==0){\n                if(grid[i][1]==-1) return 'R';\n                return '.';\n            } else { // c==1\n                if(grid[i][1]==-1) return 'Q';\n                return '.';\n            }\n        } else {\n            if(c==1) return 'L';\n            // c==0\n            if(grid[i][0]!=-1 && grid[i][1]==-1) return 'P';\n            return '.';\n        }\n    }\n\n    // Panic: drop held container (should be safe), then bomb.\n    char decideSmallPanic(int i) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n        if(cr.holding){\n            if(grid[cr.r][cr.c]==-1) return 'Q';\n            return '.';\n        }\n        return 'B';\n    }\n\n    // ===== dispatch candidate selection =====\n    int chooseBestExpectedOnGrid() const {\n        const Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n\n        int bestId=-1;\n        int bestCost=1e9;\n\n        for(int r=0;r<N;r++){\n            for(int c=0;c<4;c++){\n                int id = grid[r][c];\n                if(id==-1) continue;\n\n                if(!panic){\n                    if(r>0 && c==0) continue;\n                    if(r>0 && c==1){\n                        const Crane &s = cranes[r];\n                        if(!(s.alive && s.r==r && s.c==0 && !s.holding)) continue;\n                    }\n                }\n\n                int t = id / N;\n                if(expectedId(t) != id) continue;\n\n                int d1 = estDistLarge(lr,lc,r,c);\n                int d2 = estDistLarge(r,c,t,4);\n                if(d1>=1e9 || d2>=1e9) continue;\n                int cost = d1 + d2;\n                if(cost < bestCost){\n                    bestCost = cost;\n                    bestId = id;\n                }\n            }\n        }\n        return bestId;\n    }\n\n    int chooseBestOutOfOrderOnGrid(int maxInvAllowed) const {\n        const Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n\n        long long bestScore = (1LL<<60);\n        int bestId=-1;\n\n        for(int r=0;r<N;r++){\n            for(int c=0;c<4;c++){\n                int id = grid[r][c];\n                if(id==-1) continue;\n\n                if(!panic){\n                    if(r>0 && c==0) continue;\n                    if(r>0 && c==1){\n                        const Crane &s = cranes[r];\n                        if(!(s.alive && s.r==r && s.c==0 && !s.holding)) continue;\n                    }\n                }\n\n                int inv = invCostIfDispatch(id);\n                if(inv > maxInvAllowed) continue;\n\n                int t=id/N;\n                int d1 = estDistLarge(lr,lc,r,c);\n                int d2 = estDistLarge(r,c,t,4);\n                if(d1>=1e9 || d2>=1e9) continue;\n\n                bool isExp = (expectedId(t)==id);\n                long long score = 100000LL*inv + 10LL*(d1+d2) + (isExp?0:50);\n                if(score < bestScore){\n                    bestScore = score;\n                    bestId = id;\n                }\n            }\n        }\n        return bestId;\n    }\n\n    // ===== plan builders =====\n    bool buildDispatchPlanFrom(int pr,int pc,int id){\n        plan0.clear();\n        Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n        int t = id / N;\n\n        auto p1 = bfsPathLarge(lr,lc,pr,pc);\n        if(!(lr==pr && lc==pc) && p1.empty()) return false;\n        auto p2 = bfsPathLarge(pr,pc,t,4);\n        if(!(pr==t && pc==4) && p2.empty()) return false;\n\n        for(char m: p1) plan0.push_back(m);\n        plan0.push_back('P');\n        for(char m: p2) plan0.push_back(m);\n        plan0.push_back('Q');\n        return true;\n    }\n\n    bool buildPickStorePlan(int pr,int pc){\n        plan0.clear();\n        Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n        int id = grid[pr][pc];\n        if(id==-1) return false;\n\n        // require buffer pickup safety in normal mode\n        if(!panic){\n            if(pr>0 && pc==1){\n                const Crane &s = cranes[pr];\n                if(!(s.alive && s.r==pr && s.c==0 && !s.holding)) return false;\n            }\n            if(pr>0 && pc==0) return false;\n        }\n\n        auto st = chooseStorageCellFor(id, pr, pc);\n        if(st.first==-1) return false;\n\n        auto p1 = bfsPathLarge(lr,lc,pr,pc);\n        if(!(lr==pr && lc==pc) && p1.empty()) return false;\n        auto p2 = bfsPathLarge(pr,pc,st.first,st.second);\n        if(!(pr==st.first && pc==st.second) && p2.empty()) return false;\n\n        for(char m: p1) plan0.push_back(m);\n        plan0.push_back('P');\n        for(char m: p2) plan0.push_back(m);\n        plan0.push_back('Q');\n        return true;\n    }\n\n    void buildLargePlan(){\n        plan0.clear();\n        Crane &L = cranes[0];\n\n        // If holding: DO NOT dispatch unless it is expected or we have no storage (or in panic).\n        if(L.holding){\n            int id = L.held;\n            int t = id / N;\n            bool isExp = (expectedId(t) == id);\n\n            // Try store first if not expected (reduces inversions)\n            if(!panic && !isExp){\n                auto st = chooseStorageCellFor(id, L.r, L.c);\n                if(st.first!=-1){\n                    auto p = bfsPathLarge(L.r,L.c,st.first,st.second);\n                    for(char m: p) plan0.push_back(m);\n                    plan0.push_back('Q');\n                    return;\n                }\n                // no storage -> must dispatch (emergency)\n            }\n\n            // dispatch (panic or expected or no storage)\n            auto p2 = bfsPathLarge(L.r,L.c,t,4);\n            for(char m: p2) plan0.push_back(m);\n            plan0.push_back('Q');\n            return;\n        }\n\n        // 1) dispatch an expected container if possible\n        int expId = chooseBestExpectedOnGrid();\n        if(expId!=-1){\n            int pr = posR[expId], pc = posC[expId];\n            if(pr!=-1 && buildDispatchPlanFrom(pr,pc,expId)) return;\n        }\n\n        // 2) In panic: dispatch something (min inversions), to finish surely\n        if(panic){\n            int any = chooseBestOutOfOrderOnGrid(4);\n            if(any!=-1){\n                int pr=posR[any], pc=posC[any];\n                if(pr!=-1 && buildDispatchPlanFrom(pr,pc,any)) return;\n            }\n        }\n\n        // 3) Free a full buffer by moving it into storage\n        int lr=L.r, lc=L.c;\n        int bestRow=-1, bestD=1e9;\n        for(int i=1;i<N;i++){\n            if(grid[i][1]==-1) continue;\n            const Crane &s = cranes[i];\n            if(!panic && !(s.alive && s.r==i && s.c==0 && !s.holding)) continue;\n            int d = estDistLarge(lr,lc,i,1);\n            if(d < bestD){\n                bestD = d;\n                bestRow = i;\n            }\n        }\n        if(bestRow!=-1){\n            // if it is expected, dispatch directly (already handled by expected scan, but keep as safety)\n            int id = grid[bestRow][1];\n            if(id!=-1 && expectedId(id/N)==id){\n                if(buildDispatchPlanFrom(bestRow,1,id)) return;\n            }\n            if(buildPickStorePlan(bestRow,1)) return;\n        }\n\n        // 4) Clear row0 gate (only large can do this)\n        if(grid[0][0]!=-1){\n            int id = grid[0][0];\n            if(id!=-1 && expectedId(id/N)==id){\n                if(buildDispatchPlanFrom(0,0,id)) return;\n            }\n            if(buildPickStorePlan(0,0)) return;\n        }\n\n        // 5) Emergency in normal mode: if no storage exists AND no expected, dispatch low-inversion container\n        if(!panic){\n            if(countEmptyStorageCells() == 0){\n                int any = chooseBestOutOfOrderOnGrid(1); // try very conservative\n                if(any==-1) any = chooseBestOutOfOrderOnGrid(4);\n                if(any!=-1){\n                    int pr=posR[any], pc=posC[any];\n                    if(pr!=-1 && buildDispatchPlanFrom(pr,pc,any)) return;\n                }\n            }\n        }\n\n        plan0.push_back('.');\n    }\n\n    // ===== legality checking & simulation =====\n    struct MoveInfo { int sr,sc, dr,dc; };\n\n    bool validateActions(const array<char,N>& act) const {\n        array<MoveInfo,N> mv;\n        array<bool,N> willBomb{};\n        for(int k=0;k<N;k++){\n            const Crane &cr = cranes[k];\n            willBomb[k]=false;\n\n            if(!cr.alive){\n                if(act[k] != '.') return false;\n                mv[k]={cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n\n            char a = act[k];\n            if(a=='B'){\n                if(cr.holding) return false;\n                willBomb[k]=true;\n                mv[k]={cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n\n            int r=cr.r,c=cr.c,nr=r,nc=c;\n            if(a=='U') nr--;\n            else if(a=='D') nr++;\n            else if(a=='L') nc--;\n            else if(a=='R') nc++;\n            else if(a=='P'||a=='Q'||a=='.') {}\n            else return false;\n\n            if(nr<0||nr>=N||nc<0||nc>=N) return false;\n\n            if((a=='U'||a=='D'||a=='L'||a=='R') && !cr.large && cr.holding){\n                if(grid[nr][nc]!=-1) return false;\n            }\n            if(a=='P'){\n                if(cr.holding) return false;\n                if(grid[r][c]==-1) return false;\n            }\n            if(a=='Q'){\n                if(!cr.holding) return false;\n                if(grid[r][c]!=-1) return false;\n            }\n            mv[k]={r,c,nr,nc};\n        }\n\n        // overlap after move among non-bombed cranes\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                if(mv[i].dr==mv[j].dr && mv[i].dc==mv[j].dc) return false;\n            }\n        }\n        // swap (passing)\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                bool sw = (mv[i].dr==mv[j].sr && mv[i].dc==mv[j].sc &&\n                           mv[j].dr==mv[i].sr && mv[j].dc==mv[i].sc &&\n                           !(mv[i].sr==mv[j].sr && mv[i].sc==mv[j].sc));\n                if(sw) return false;\n            }\n        }\n        return true;\n    }\n\n    void applyActions(const array<char,N>& act){\n        array<bool,N> willBomb{};\n        array<int,N> nr, nc;\n        for(int k=0;k<N;k++){\n            nr[k]=cranes[k].r;\n            nc[k]=cranes[k].c;\n            willBomb[k]=false;\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            if(a=='B'){ willBomb[k]=true; continue; }\n            if(a=='U') nr[k]--;\n            else if(a=='D') nr[k]++;\n            else if(a=='L') nc[k]--;\n            else if(a=='R') nc[k]++;\n        }\n\n        // bombs first (allows others to move into the bombed cell)\n        for(int k=0;k<N;k++){\n            if(cranes[k].alive && willBomb[k]) cranes[k].alive=false;\n        }\n\n        // moves\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(act[k]=='B') continue;\n            cranes[k].r = nr[k];\n            cranes[k].c = nc[k];\n        }\n\n        // P/Q\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            int r=cranes[k].r, c=cranes[k].c;\n            if(a=='P'){\n                int id = grid[r][c];\n                grid[r][c] = -1;\n                posR[id]=posC[id]=-1;\n                cranes[k].holding=true;\n                cranes[k].held=id;\n            } else if(a=='Q'){\n                int id = cranes[k].held;\n                grid[r][c] = id;\n                posR[id]=r; posC[id]=c;\n                cranes[k].holding=false;\n                cranes[k].held=-1;\n            }\n        }\n\n        // dispatch at col 4\n        for(int r=0;r<N;r++){\n            int id = grid[r][4];\n            if(id==-1) continue;\n            grid[r][4] = -1;\n            posR[id]=posC[id]=-1;\n            int t=id/N, idx=id%N;\n            if(((dispMask[t]>>idx)&1)==0){\n                dispMask[t] |= (1<<idx);\n                dispatchedCount++;\n            }\n        }\n    }\n\n    void run(){\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            // step1 spawn\n            spawnPhase();\n\n            // panic detection\n            if(dispatchedCount != lastDispatchedCount){\n                lastDispatchedCount = dispatchedCount;\n                noDispatchTurns = 0;\n            } else {\n                noDispatchTurns++;\n            }\n            if(!panic && (noDispatchTurns >= STUCK_LIMIT || turn >= LATE_LIMIT)){\n                panic = true;\n                plan0.clear();\n            }\n\n            // decide large action\n            if(plan0.empty()) buildLargePlan();\n            array<char,N> act; act.fill('.');\n            act[0] = plan0.empty()?'.':plan0.front();\n\n            // lock row if large is/will be on (row>0,col=1) to avoid collision with small\n            int lockRow=-1;\n            if(cranes[0].alive){\n                int lr=cranes[0].r, lc=cranes[0].c;\n                int dr=lr, dc=lc;\n                if(act[0]=='U') dr--;\n                else if(act[0]=='D') dr++;\n                else if(act[0]=='L') dc--;\n                else if(act[0]=='R') dc++;\n                if(dr>0 && dc==1) lockRow=dr;\n                if(lr>0 && lc==1 && (act[0]=='.' || act[0]=='P' || act[0]=='Q')) lockRow=lr;\n            }\n\n            // decide small actions\n            for(int i=1;i<N;i++){\n                act[i] = panic ? decideSmallPanic(i) : decideSmallNormal(i, lockRow);\n            }\n\n            // validate & fallback\n            if(!validateActions(act)){\n                array<char,N> act2 = act;\n                for(int i=1;i<N;i++) act2[i]='.'; // freeze smalls\n                if(validateActions(act2)){\n                    act = act2;\n                } else {\n                    array<char,N> act3; act3.fill('.');\n                    act = act3;\n                }\n            }\n\n            // consume plan step\n            if(!plan0.empty() && act[0]==plan0.front()){\n                plan0.pop_front();\n            } else if(!plan0.empty() && act[0] != '.'){\n                plan0.clear();\n            }\n\n            // output\n            for(int i=0;i<N;i++) out[i].push_back(act[i]);\n\n            // step2+3\n            applyActions(act);\n\n            turn++;\n        }\n\n        if(turn==0){\n            for(int i=0;i<N;i++) out[i].push_back('.');\n        }\n    }\n\n    void print() const {\n        for(int i=0;i<N;i++) cout << out[i] << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<vector<int>> Ain(n, vector<int>(n));\n    for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin >> Ain[i][j];\n\n    Solver solver(Ain);\n    solver.run();\n    solver.print();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF = (1LL<<62);\n\nstatic inline int id(int r, int c, int N){ return r*N + c; }\nstatic inline int r_of(int v, int N){ return v / N; }\nstatic inline int c_of(int v, int N){ return v % N; }\n\nstatic inline char move_dir(int from, int to, int N){\n    int fr = r_of(from, N), fc = c_of(from, N);\n    int tr = r_of(to, N), tc = c_of(to, N);\n    if (tr == fr-1 && tc == fc) return 'U';\n    if (tr == fr+1 && tc == fc) return 'D';\n    if (tr == fr && tc == fc-1) return 'L';\n    if (tr == fr && tc == fc+1) return 'R';\n    return '?';\n}\n\nstruct Emitter {\n    vector<string> ops;\n    void emit_move(char c) { ops.emplace_back(1, c); }\n    void emit_amount(char sign, long long d) {\n        while (d > 0) {\n            long long x = min(d, 1000000LL);\n            ops.push_back(string(1, sign) + to_string(x));\n            d -= x;\n        }\n    }\n};\n\n// perms for k<=4\nstatic array<vector<array<int,4>>, 5> PERMS;\nstatic void init_perms(){\n    for(int k=0;k<=4;k++){\n        vector<int> v(k);\n        iota(v.begin(), v.end(), 0);\n        do{\n            array<int,4> p{};\n            for(int i=0;i<k;i++) p[i]=v[i];\n            PERMS[k].push_back(p);\n        }while(next_permutation(v.begin(), v.end()));\n    }\n}\n\nstatic inline bool would_create_cycle(const vector<int>& parent, int u, int newp){\n    int x = newp;\n    while(x != -1){\n        if(x == u) return true;\n        x = parent[x];\n    }\n    return false;\n}\n\nstruct Plan {\n    long long cost = INF;\n    array<array<int,4>, 400> order{}; // ordered children\n    array<uint8_t, 400> deg{};\n    array<long long, 400> need{};\n    vector<int> parent;\n};\n\nstruct TreeEvaluator {\n    int N, V;\n    const vector<int> *h;\n\n    // work buffers (fixed size because N=20 => V=400)\n    array<array<int,4>, 400> child{};\n    array<uint8_t, 400> deg{};\n    array<uint8_t, 400> it{};\n    array<int, 400> st{};\n    array<int, 400> post{};\n    array<long long, 400> subsum{}, need{}, out{}, dp{};\n\n    TreeEvaluator(int N, const vector<int>& h): N(N), V(N*N), h(&h) {}\n\n    long long eval_cost(const vector<int>& parent){\n        // build children\n        for(int i=0;i<V;i++) deg[i]=0;\n        for(int v=1; v<V; v++){\n            int p = parent[v];\n            if(p < 0) return INF;\n            if(deg[p] >= 4) return INF;\n            child[p][deg[p]++] = v;\n        }\n        // postorder iterative DFS from 0\n        for(int i=0;i<V;i++) it[i]=0;\n        int top=0, ptop=0;\n        st[top++] = 0;\n        while(top){\n            int v = st[top-1];\n            if(it[v] < deg[v]){\n                int c = child[v][it[v]++];\n                st[top++] = c;\n            }else{\n                post[ptop++] = v;\n                top--;\n            }\n        }\n        if(ptop != V) return INF;\n\n        // subsum\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            long long s = (*h)[v];\n            for(int i=0;i<deg[v];i++) s += subsum[child[v][i]];\n            subsum[v] = s;\n        }\n        if(subsum[0] != 0) return INF;\n        for(int v=0; v<V; v++){\n            need[v] = max(0LL, -subsum[v]);\n            out[v]  = max(0LL,  subsum[v]);\n        }\n\n        // dp\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            int k = deg[v];\n\n            long long base = 0;\n            for(int i=0;i<k;i++){\n                int c = child[v][i];\n                long long dc = dp[c];\n                if(dc >= INF/4){ base = INF; break; }\n                base += dc;\n                base += 200 + need[c] + out[c];\n                if(base >= INF/4){ base = INF; break; }\n            }\n            if(base >= INF/4){ dp[v] = INF; continue; }\n\n            long long best = INF;\n\n            if(k == 0){\n                long long curH = (*h)[v];\n                long long load = need[v];\n                long long cost = 0;\n                if(curH > 0){\n                    cost += curH;\n                    load += curH;\n                }else if(curH < 0){\n                    long long x = -curH;\n                    cost += x;\n                    load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n                dp[v] = cost;\n                continue;\n            }\n\n            // children list compact\n            int kids[4];\n            for(int i=0;i<k;i++) kids[i] = child[v][i];\n\n            for(const auto &perm : PERMS[k]){\n                long long curH = (*h)[v];\n                long long load = need[v];\n                long long cost = base;\n\n                for(int j=0;j<k;j++){\n                    int c = kids[perm[j]];\n                    long long target = need[c];\n                    if(load < target){\n                        long long d = target - load;\n                        cost += d;\n                        curH -= d;\n                        load = target;\n                    }else if(load > target){\n                        long long d = load - target;\n                        cost += d;\n                        curH += d;\n                        load = target;\n                    }\n                    load = out[c];\n                }\n\n                if(curH > 0){\n                    cost += curH;\n                    load += curH;\n                }else if(curH < 0){\n                    long long x = -curH;\n                    cost += x;\n                    load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n\n                if(cost < best) best = cost;\n            }\n\n            dp[v] = best;\n        }\n\n        return dp[0];\n    }\n\n    Plan build_plan(const vector<int>& parent){\n        Plan plan;\n        plan.parent = parent;\n\n        // build children\n        for(int i=0;i<V;i++) deg[i]=0;\n        for(int v=1; v<V; v++){\n            int p = parent[v];\n            child[p][deg[p]++] = v;\n        }\n\n        // postorder\n        for(int i=0;i<V;i++) it[i]=0;\n        int top=0, ptop=0;\n        st[top++] = 0;\n        while(top){\n            int v = st[top-1];\n            if(it[v] < deg[v]){\n                int c = child[v][it[v]++];\n                st[top++] = c;\n            }else{\n                post[ptop++] = v;\n                top--;\n            }\n        }\n\n        // subsum, need/out\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            long long s = (*h)[v];\n            for(int i=0;i<deg[v];i++) s += subsum[child[v][i]];\n            subsum[v] = s;\n        }\n        for(int v=0; v<V; v++){\n            plan.need[v] = max(0LL, -subsum[v]);\n            out[v]       = max(0LL,  subsum[v]);\n            plan.deg[v]  = deg[v];\n        }\n\n        // dp + best order\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            int k = deg[v];\n\n            long long base = 0;\n            for(int i=0;i<k;i++){\n                int c = child[v][i];\n                base += dp[c];\n                base += 200 + plan.need[c] + out[c];\n            }\n\n            long long best = INF;\n            array<int,4> bestOrd{};\n\n            if(k == 0){\n                best = llabs((long long)(*h)[v]);\n                plan.order[v] = bestOrd;\n                dp[v] = best;\n                continue;\n            }\n\n            int kids[4];\n            for(int i=0;i<k;i++) kids[i] = child[v][i];\n\n            for(const auto &perm : PERMS[k]){\n                long long curH = (*h)[v];\n                long long load = plan.need[v];\n                long long cost = base;\n\n                for(int j=0;j<k;j++){\n                    int c = kids[perm[j]];\n                    long long target = plan.need[c];\n                    if(load < target){\n                        long long d = target - load;\n                        cost += d;\n                        curH -= d;\n                        load = target;\n                    }else if(load > target){\n                        long long d = load - target;\n                        cost += d;\n                        curH += d;\n                        load = target;\n                    }\n                    load = out[c];\n                }\n\n                if(curH > 0){\n                    cost += curH;\n                    load += curH;\n                }else if(curH < 0){\n                    long long x = -curH;\n                    cost += x;\n                    load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n\n                if(cost < best){\n                    best = cost;\n                    for(int j=0;j<k;j++) bestOrd[j] = kids[perm[j]];\n                }\n            }\n\n            plan.order[v] = bestOrd;\n            dp[v] = best;\n        }\n\n        plan.cost = dp[0];\n        return plan;\n    }\n};\n\nstatic void build_ops_from_plan(const Plan& plan, const vector<int>& h, int N, vector<string>& out_ops){\n    int V = N*N;\n    vector<long long> curH(V);\n    for(int i=0;i<V;i++) curH[i] = h[i];\n\n    Emitter em;\n    long long load = 0;\n\n    struct Frame{ int v; int idx; };\n    array<Frame, 410> st;\n    int sp=0;\n    st[sp++] = {0,0};\n\n    while(sp){\n        int v = st[sp-1].v;\n        int &idx = st[sp-1].idx;\n        int k = plan.deg[v];\n\n        if(idx < k){\n            int c = plan.order[v][idx++];\n            long long target = plan.need[c];\n\n            if(load < target){\n                long long d = target - load;\n                em.emit_amount('+', d);\n                curH[v] -= d;\n                load = target;\n            }else if(load > target){\n                long long d = load - target;\n                em.emit_amount('-', d);\n                curH[v] += d;\n                load = target;\n            }\n\n            em.emit_move(move_dir(v, c, N));\n            st[sp++] = {c,0};\n        }else{\n            // fix v to 0\n            if(curH[v] > 0){\n                long long x = curH[v];\n                em.emit_amount('+', x);\n                load += x;\n                curH[v] = 0;\n            }else if(curH[v] < 0){\n                long long x = -curH[v];\n                em.emit_amount('-', x);\n                load -= x;\n                curH[v] = 0;\n            }\n\n            sp--;\n            if(sp==0) break;\n            int p = st[sp-1].v;\n            em.emit_move(move_dir(v, p, N));\n        }\n    }\n\n    out_ops = std::move(em.ops);\n}\n\n// generators\nstatic vector<int> bfs_tree(int N, const array<int,4>& ord){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        int r=r_of(v,N), c=c_of(v,N);\n        for(int t: ord){\n            int nr=r, nc=c;\n            if(t==0) nr--;\n            if(t==1) nr++;\n            if(t==2) nc--;\n            if(t==3) nc++;\n            if(nr<0||nr>=N||nc<0||nc>=N) continue;\n            int u=id(nr,nc,N);\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstruct DSU{\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(),p.end(),0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstatic vector<int> random_kruskal_tree(int V, const vector<pair<int,int>>& edges, mt19937_64& rng){\n    vector<pair<int,int>> e = edges;\n    shuffle(e.begin(), e.end(), rng);\n    DSU dsu(V);\n    vector<vector<int>> g(V);\n    g.assign(V, {});\n    int used=0;\n    for(auto [a,b]: e){\n        if(dsu.unite(a,b)){\n            g[a].push_back(b);\n            g[b].push_back(a);\n            if(++used == V-1) break;\n        }\n    }\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        for(int u: g[v]){\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstatic vector<int> biased_prim_tree(int N, const vector<int>& h, mt19937_64& rng){\n    int V = N*N;\n    vector<char> in(V, 0);\n    vector<int> parent(V, -1);\n\n    vector<int> pos(V, -1);\n    vector<int> frontier;\n    frontier.reserve(V);\n    vector<array<int,4>> candP(V);\n    vector<uint8_t> ccnt(V, 0);\n\n    auto add_front = [&](int u, int p){\n        if(in[u]) return;\n        if(pos[u] == -1){\n            pos[u] = (int)frontier.size();\n            frontier.push_back(u);\n        }\n        if(ccnt[u] < 4) candP[u][ccnt[u]++] = p;\n    };\n    auto pop_front = [&](int u){\n        int i = pos[u];\n        int last = frontier.back();\n        frontier[i] = last;\n        pos[last] = i;\n        frontier.pop_back();\n        pos[u] = -1;\n    };\n    auto try_add_neighbors = [&](int v){\n        int r=r_of(v,N), c=c_of(v,N);\n        if(r>0) add_front(id(r-1,c,N), v);\n        if(r+1<N) add_front(id(r+1,c,N), v);\n        if(c>0) add_front(id(r,c-1,N), v);\n        if(c+1<N) add_front(id(r,c+1,N), v);\n    };\n\n    in[0]=1;\n    try_add_neighbors(0);\n\n    int added=1;\n    while(added < V){\n        int u = frontier[uniform_int_distribution<int>(0, (int)frontier.size()-1)(rng)];\n        // choose parent among candP[u] by weight\n        long long tot=0;\n        long long w[4];\n        for(int i=0;i<ccnt[u];i++){\n            int p = candP[u][i];\n            long long ww = 1;\n            if(h[u]!=0 && h[p]!=0 && (long long)h[u]*h[p] < 0) ww += 6;\n            ww += (abs(h[u]) + abs(h[p]) >= 120 ? 2 : 0);\n            w[i]=ww;\n            tot += ww;\n        }\n        long long x = uniform_int_distribution<long long>(1, tot)(rng);\n        int psel = candP[u][0];\n        for(int i=0;i<ccnt[u];i++){\n            x -= w[i];\n            if(x <= 0){\n                psel = candP[u][i];\n                break;\n            }\n        }\n\n        parent[u] = psel;\n        in[u]=1;\n        added++;\n\n        pop_front(u);\n        ccnt[u]=0;\n        try_add_neighbors(u);\n    }\n\n    return parent;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_perms();\n\n    int N;\n    cin >> N;\n    int V = N*N;\n    vector<int> h(V);\n    for(int i=0;i<N;i++){\n        for(int j=0;j<N;j++){\n            cin >> h[id(i,j,N)];\n        }\n    }\n\n    // edges for Kruskal\n    vector<pair<int,int>> edges;\n    edges.reserve(2*N*(N-1));\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v=id(r,c,N);\n            if(r+1<N) edges.push_back({v, id(r+1,c,N)});\n            if(c+1<N) edges.push_back({v, id(r,c+1,N)});\n        }\n    }\n\n    // adjacency list as arrays for SA proposal\n    array<array<int,4>, 400> adj{};\n    array<uint8_t, 400> adeg{};\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v=id(r,c,N);\n            uint8_t k=0;\n            if(r>0) adj[v][k++]=id(r-1,c,N);\n            if(r+1<N) adj[v][k++]=id(r+1,c,N);\n            if(c>0) adj[v][k++]=id(r,c-1,N);\n            if(c+1<N) adj[v][k++]=id(r,c+1,N);\n            adeg[v]=k;\n        }\n    }\n\n    mt19937_64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n    const double TL = 1.95;\n\n    TreeEvaluator eval(N, h);\n\n    vector<int> best_parent;\n    long long best_cost = INF;\n\n    auto consider = [&](const vector<int>& parent){\n        long long c = eval.eval_cost(parent);\n        if(c < best_cost){\n            best_cost = c;\n            best_parent = parent;\n        }\n    };\n\n    // initial pool\n    {\n        array<array<int,4>,4> orders = {{\n            {3,1,2,0}, {1,3,2,0}, {3,2,1,0}, {1,2,3,0}\n        }};\n        for(auto ord: orders) consider(bfs_tree(N, ord));\n        for(int i=0;i<30;i++) consider(random_kruskal_tree(V, edges, rng));\n        for(int i=0;i<40;i++) consider(biased_prim_tree(N, h, rng));\n    }\n    if(best_parent.empty()){\n        best_parent = bfs_tree(N, {3,1,2,0});\n        best_cost = eval.eval_cost(best_parent);\n    }\n\n    // SA on re-parenting\n    vector<int> cur_parent = best_parent;\n    long long cur_cost = best_cost;\n\n    long long iter=0;\n    while(elapsed() < TL){\n        iter++;\n        double t = elapsed() / TL;\n        double T0 = 2500.0, T1 = 10.0;\n        double temp = T0*(1.0-t) + T1*t;\n\n        if((iter % 8000) == 0){\n            // periodic reset to best to intensify\n            cur_parent = best_parent;\n            cur_cost = best_cost;\n        }\n\n        int u = uniform_int_distribution<int>(1, V-1)(rng);\n\n        // propose new parent biased to opposite sign\n        int k = adeg[u];\n        int cand = adj[u][uniform_int_distribution<int>(0, k-1)(rng)];\n        // one extra try for bias\n        int cand2 = adj[u][uniform_int_distribution<int>(0, k-1)(rng)];\n        auto score_nb = [&](int p){\n            long long s=0;\n            if(h[u]!=0 && h[p]!=0 && (long long)h[u]*h[p] < 0) s += 5;\n            s += (abs(h[p]) >= 60 ? 1 : 0);\n            return s;\n        };\n        int newp = (score_nb(cand2) > score_nb(cand) ? cand2 : cand);\n\n        if(newp == cur_parent[u]) continue;\n        if(would_create_cycle(cur_parent, u, newp)) continue;\n\n        int oldp = cur_parent[u];\n        cur_parent[u] = newp;\n\n        long long nxt_cost = eval.eval_cost(cur_parent);\n        if(nxt_cost >= INF/2){\n            cur_parent[u] = oldp;\n            continue;\n        }\n\n        bool accept = false;\n        if(nxt_cost <= cur_cost) accept = true;\n        else{\n            double diff = (double)(cur_cost - nxt_cost); // negative\n            double prob = exp(diff / temp);\n            if(uniform_real_distribution<double>(0.0, 1.0)(rng) < prob) accept = true;\n        }\n\n        if(accept){\n            cur_cost = nxt_cost;\n            if(cur_cost < best_cost){\n                best_cost = cur_cost;\n                best_parent = cur_parent;\n            }\n        }else{\n            cur_parent[u] = oldp;\n        }\n    }\n\n    // build plan and output\n    Plan plan = eval.build_plan(best_parent);\n\n    vector<string> ops;\n    build_ops_from_plan(plan, h, N, ops);\n\n    if((int)ops.size() > 100000) ops.clear();\n    for(auto &s: ops) cout << s << \"\\n\";\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ull;\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n};\n\nstatic constexpr int MMAX = 15;\n\nstruct Seed {\n    array<uint8_t, MMAX> x{};\n    int V = 0;\n    int peak = 0;\n};\n\nstatic inline int diffCount(const Seed& a, const Seed& b, int M) {\n    int d = 0;\n    for (int i = 0; i < M; i++) d += (a.x[i] != b.x[i]);\n    return d;\n}\nstatic inline int sumAbsDiff(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += abs((int)a.x[i] - (int)b.x[i]);\n    return s;\n}\nstatic inline int potentialSumMax(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += max<int>(a.x[i], b.x[i]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    using Clock = chrono::steady_clock;\n    using TimePoint = Clock::time_point;\n\n    int N, M, T;\n    cin >> N >> M >> T;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60\n    const int P = N * N;                    // 36\n\n    vector<Seed> seeds(SEED_COUNT);\n\n    auto readSeeds = [&]() {\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int sum = 0, pk = 0;\n            for (int l = 0; l < M; l++) {\n                int v;\n                cin >> v;\n                seeds[k].x[l] = (uint8_t)v;\n                sum += v;\n                pk = max(pk, v);\n            }\n            seeds[k].V = sum;\n            seeds[k].peak = pk;\n        }\n    };\n\n    readSeeds();\n\n    // Grid neighbors and edges\n    vector<vector<int>> neigh(P);\n    vector<pair<int,int>> edges;\n    vector<int> degree(P, 0);\n    auto id = [&](int i, int j) { return i * N + j; };\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int v = id(i, j);\n            if (i > 0) neigh[v].push_back(id(i - 1, j));\n            if (i + 1 < N) neigh[v].push_back(id(i + 1, j));\n            if (j > 0) neigh[v].push_back(id(i, j - 1));\n            if (j + 1 < N) neigh[v].push_back(id(i, j + 1));\n            degree[v] = (int)neigh[v].size();\n        }\n    }\n    for (int i = 0; i < N; i++)\n        for (int j = 0; j + 1 < N; j++)\n            edges.push_back({id(i, j), id(i, j + 1)});\n    for (int i = 0; i + 1 < N; i++)\n        for (int j = 0; j < N; j++)\n            edges.push_back({id(i, j), id(i + 1, j)});\n\n    vector<int> posOrder(P);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n        if (degree[a] != degree[b]) return degree[a] > degree[b];\n        return a < b;\n    });\n\n    vector<int> centers;\n    for (int p = 0; p < P; p++) if (degree[p] == 4) centers.push_back(p);\n\n    RNG rng;\n    TimePoint globalStart = Clock::now();\n    const double TIME_LIMIT = 1.90;\n\n    auto evalObjective = [&](const vector<int>& perm,\n                             const vector<vector<double>>& w,\n                             const vector<int>& impLocal,\n                             double alphaUnary) -> double {\n        double s = 0.0;\n        for (auto [u, v] : edges) s += w[perm[u]][perm[v]];\n        if (alphaUnary > 0) {\n            for (int pos = 0; pos < P; pos++) s += alphaUnary * (double)degree[pos] * (double)impLocal[perm[pos]];\n        }\n        return s;\n    };\n\n    auto runSA = [&](vector<int> perm,\n                     const vector<vector<double>>& w,\n                     const vector<int>& impLocal,\n                     double alphaUnary,\n                     TimePoint endTime) -> pair<double, vector<int>> {\n        double cur = evalObjective(perm, w, impLocal, alphaUnary);\n        double best = cur;\n        vector<int> bestPerm = perm;\n\n        const double tempStart = 520.0;\n        const double tempEnd = 12.0;\n\n        TimePoint t0 = Clock::now();\n        double total = chrono::duration<double>(endTime - t0).count();\n        if (total <= 1e-9) return {cur, perm};\n\n        while (Clock::now() < endTime) {\n            int a = rng.nextInt(P);\n            int b = rng.nextInt(P);\n            if (a == b) continue;\n\n            int la = perm[a];\n            int lb = perm[b];\n\n            double delta = 0.0;\n            // edge deltas\n            for (int na : neigh[a]) {\n                if (na == b) continue;\n                int lx = perm[na];\n                delta += w[lb][lx] - w[la][lx];\n            }\n            for (int nb : neigh[b]) {\n                if (nb == a) continue;\n                int lx = perm[nb];\n                delta += w[la][lx] - w[lb][lx];\n            }\n\n            // unary delta\n            if (alphaUnary > 0) {\n                double da = alphaUnary * (double)degree[a];\n                double db = alphaUnary * (double)degree[b];\n                delta += da * ((double)impLocal[lb] - (double)impLocal[la])\n                      +  db * ((double)impLocal[la] - (double)impLocal[lb]);\n            }\n\n            double prog = chrono::duration<double>(Clock::now() - t0).count() / total;\n            prog = min(1.0, max(0.0, prog));\n            double temp = tempStart * pow(tempEnd / tempStart, prog);\n\n            bool accept = (delta >= 0.0) || (rng.nextDouble() < exp(delta / temp));\n            if (accept) {\n                swap(perm[a], perm[b]);\n                cur += delta;\n                if (cur > best) {\n                    best = cur;\n                    bestPerm = perm;\n                }\n            }\n        }\n        return {best, bestPerm};\n    };\n\n    for (int t = 0; t < T; t++) {\n        // per-turn budget\n        double elapsed = chrono::duration<double>(Clock::now() - globalStart).count();\n        double remaining = max(0.0, TIME_LIMIT - elapsed);\n        double perTurn = remaining / max(1, (T - t));\n        TimePoint turnStart = Clock::now();\n        TimePoint turnEnd = turnStart + chrono::duration_cast<Clock::duration>(chrono::duration<double>(perTurn * 0.97));\n\n        double phase = (T == 1) ? 1.0 : (double)t / (double)(T - 1);\n\n        // ---- Selection (revert to stable, high-V focused) ----\n        vector<int> idx(SEED_COUNT);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (seeds[a].V != seeds[b].V) return seeds[a].V > seeds[b].V;\n            return a < b;\n        });\n\n        const int eliteCount = 10;\n        const int partnerFor = 8;\n        const int perDimTake = 1;\n\n        vector<int> selected;\n        selected.reserve(P);\n        vector<char> used(SEED_COUNT, 0), prot(SEED_COUNT, 0);\n\n        auto addSeed = [&](int k, bool protect) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n            if (protect) prot[k] = 1;\n        };\n\n        for (int i = 0; i < eliteCount; i++) addSeed(idx[i], true);\n\n        for (int i = 0; i < partnerFor; i++) {\n            int e = idx[i];\n            int best = -1;\n            int bestScore = INT_MAX;\n            for (int j = 0; j < SEED_COUNT; j++) {\n                if (j == e || used[j]) continue;\n                int d = diffCount(seeds[e], seeds[j], M);\n                int vd = abs(seeds[e].V - seeds[j].V);\n                int score = d * 120 + vd;\n                if (score < bestScore || (score == bestScore && seeds[j].V > (best == -1 ? -1 : seeds[best].V))) {\n                    bestScore = score;\n                    best = j;\n                }\n            }\n            if (best != -1) addSeed(best, true);\n        }\n\n        for (int l = 0; l < M; l++) {\n            int best = -1;\n            for (int k = 0; k < SEED_COUNT; k++) {\n                if (used[k]) continue;\n                if (best == -1 ||\n                    seeds[k].x[l] > seeds[best].x[l] ||\n                    (seeds[k].x[l] == seeds[best].x[l] && seeds[k].V > seeds[best].V)) {\n                    best = k;\n                }\n            }\n            if (best != -1) addSeed(best, false);\n        }\n\n        auto mixedScore = [&](int k) -> int { return seeds[k].V * 10 + seeds[k].peak * 6; };\n        vector<int> rest;\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        sort(rest.begin(), rest.end(), [&](int a, int b) {\n            int sa = mixedScore(a), sb = mixedScore(b);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n        for (int k : rest) {\n            if ((int)selected.size() >= P) break;\n            addSeed(k, false);\n        }\n\n        if ((int)selected.size() > P) {\n            auto importance = [&](int k) -> int { return seeds[k].V * 10 + seeds[k].peak * 3; };\n            vector<int> removable;\n            for (int k : selected) if (!prot[k]) removable.push_back(k);\n            sort(removable.begin(), removable.end(), [&](int a, int b) {\n                int ia = importance(a), ib = importance(b);\n                if (ia != ib) return ia < ib;\n                return a > b;\n            });\n            int ptr = 0;\n            while ((int)selected.size() > P && ptr < (int)removable.size()) {\n                int rm = removable[ptr++];\n                auto it = find(selected.begin(), selected.end(), rm);\n                if (it != selected.end()) selected.erase(it);\n            }\n            while ((int)selected.size() > P) selected.pop_back();\n        }\n\n        vector<int> globOfLocal(P);\n        for (int i = 0; i < P; i++) globOfLocal[i] = selected[i];\n\n        // local importance (used by unary term + initialization)\n        vector<int> impLocal(P);\n        for (int i = 0; i < P; i++) {\n            int g = globOfLocal[i];\n            impLocal[i] = seeds[g].V * 10 + seeds[g].peak * 3;\n        }\n\n        vector<int> localSorted(P);\n        iota(localSorted.begin(), localSorted.end(), 0);\n        sort(localSorted.begin(), localSorted.end(), [&](int a, int b) {\n            if (impLocal[a] != impLocal[b]) return impLocal[a] > impLocal[b];\n            return a < b;\n        });\n\n        // ---- Pair weights: potential-based (the strong core) ----\n        double lambdaDiff = 1.6 + 2.5 * phase;\n        double rhoMinV    = 0.06 + 0.42 * phase;\n        double muAbs      = 0.001 + 0.004 * phase;\n\n        vector<vector<double>> w(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                const Seed& A = seeds[globOfLocal[i]];\n                const Seed& B = seeds[globOfLocal[j]];\n                int pot = potentialSumMax(A, B, M);\n                int d = diffCount(A, B, M);\n                int sad = sumAbsDiff(A, B, M);\n                int mn = min(A.V, B.V);\n                double score = (double)pot + rhoMinV * (double)mn\n                             - lambdaDiff * (double)d - muAbs * (double)sad;\n                w[i][j] = w[j][i] = score;\n            }\n        }\n\n        // Unary (node) term: keep strong seeds on high-degree cells.\n        // Small coefficient to avoid distorting pair selection.\n        double alphaUnary = 0.012 + 0.010 * phase; // 0.012 -> 0.022\n\n        // ---- Initial layouts (same set as the best-performing style) ----\n        // init0: importance -> high degree\n        vector<int> init0(P);\n        for (int k = 0; k < P; k++) init0[posOrder[k]] = localSorted[k];\n\n        // init1: random permutation\n        vector<int> init1 = init0;\n        for (int i = P - 1; i > 0; i--) swap(init1[i], init1[rng.nextInt(i + 1)]);\n\n        // init2: greedy incremental\n        vector<int> init2(P, -1);\n        vector<char> used2(P, 0);\n        for (int idxPos = 0; idxPos < P; idxPos++) {\n            int pos = posOrder[idxPos];\n            int bestL = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!used2[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init2[nb] != -1) gain += w[li][init2[nb]];\n                gain += alphaUnary * (double)degree[pos] * (double)impLocal[li];\n                if (gain > bestGain) { bestGain = gain; bestL = li; }\n            }\n            init2[pos] = bestL;\n            used2[bestL] = 1;\n        }\n\n        // init3: hub around best seed at a center (structured but not too strong)\n        int champ = localSorted[0];\n        int centerPos = centers.empty() ? posOrder[0] : centers[rng.nextInt((int)centers.size())];\n        vector<int> init3(P, -1);\n        vector<char> used3(P, 0);\n        init3[centerPos] = champ;\n        used3[champ] = 1;\n\n        for (int nb : neigh[centerPos]) {\n            int best = -1;\n            double bestS = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double s = w[champ][li] + 0.001 * (double)impLocal[li];\n                if (s > bestS) { bestS = s; best = li; }\n            }\n            if (best != -1) { init3[nb] = best; used3[best] = 1; }\n        }\n        for (int pos = 0; pos < P; pos++) {\n            if (init3[pos] != -1) continue;\n            int best = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init3[nb] != -1) gain += w[li][init3[nb]];\n                gain += alphaUnary * (double)degree[pos] * (double)impLocal[li];\n                if (gain > bestGain) { bestGain = gain; best = li; }\n            }\n            init3[pos] = best;\n            used3[best] = 1;\n        }\n\n        vector<vector<int>> inits = {init0, init2, init3, init1};\n\n        // ---- Run SA on each init within time ----\n        double bestObj = -1e100;\n        vector<int> bestPerm = init0;\n\n        for (int r = 0; r < (int)inits.size(); r++) {\n            TimePoint nowR = Clock::now();\n            if (nowR >= turnEnd) break;\n            int left = (int)inits.size() - r;\n            double remSec = chrono::duration<double>(turnEnd - nowR).count();\n            TimePoint endR = nowR + chrono::duration_cast<Clock::duration>(chrono::duration<double>(remSec / left));\n            auto res = runSA(inits[r], w, impLocal, alphaUnary, endR);\n            if (res.first > bestObj) {\n                bestObj = res.first;\n                bestPerm = std::move(res.second);\n            }\n        }\n\n        // ---- Output ----\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = id(i, j);\n                int localIdx = bestPerm[pos];      // local seed index\n                int globalIdx = globOfLocal[localIdx];\n                if (j) cout << ' ';\n                cout << globalIdx;\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        readSeeds();\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int dx4[4] = {0, 1, 0, -1}; // 0=R,1=D,2=L,3=U\nstatic const int dy4[4] = {1, 0, -1, 0};\n\nstruct Leaf {\n    int len;\n    int dir;   // 0..3\n    bool hold;\n};\n\nstatic inline int ang_dist(int a, int b) {\n    int d = (a - b + 4) % 4;\n    return min(d, 4 - d);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t_start = chrono::steady_clock::now();\n    auto elapsed_sec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    const int NN = N * N;\n\n    vector<unsigned char> cur(NN, 0), target(NN, 0);\n    for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n        cur[x * N + y] = (s[x][y] == '1');\n        target[x * N + y] = (t[x][y] == '1');\n    }\n\n    // surplus: cur=1,target=0 ; deficit: cur=0,target=1\n    vector<unsigned char> isSur(NN, 0), isDef(NN, 0);\n\n    long long surCount = 0, defCount = 0;\n    long long sumSurX = 0, sumSurY = 0, sumDefX = 0, sumDefY = 0;\n\n    for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n        int idx = x * N + y;\n        if (cur[idx] && !target[idx]) {\n            isSur[idx] = 1;\n            surCount++;\n            sumSurX += x; sumSurY += y;\n        } else if (!cur[idx] && target[idx]) {\n            isDef[idx] = 1;\n            defCount++;\n            sumDefX += x; sumDefY += y;\n        }\n    }\n\n    auto inside = [&](int x, int y) -> bool {\n        return (0 <= x && x < N && 0 <= y && y < N);\n    };\n\n    // Arm design: star with V' = V\n    int Vp = V;\n    int K = Vp - 1;\n\n    // Lengths: 1..K (robust coverage, unique)\n    vector<int> lengths(K);\n    for (int i = 0; i < K; i++) lengths[i] = i + 1;\n\n    vector<Leaf> leaves(K);\n    for (int i = 0; i < K; i++) leaves[i] = Leaf{lengths[i], 0, false};\n\n    // Precompute endpoints: endIdx[leaf][rootPos][dir] = cellIndex or -1\n    vector<vector<array<int,4>>> endIdx(K, vector<array<int,4>>(NN));\n    for (int i = 0; i < K; i++) {\n        int L = leaves[i].len;\n        for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n            int p = x * N + y;\n            array<int,4> arr;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx4[d] * L;\n                int ny = y + dy4[d] * L;\n                arr[d] = inside(nx, ny) ? (nx * N + ny) : -1;\n            }\n            endIdx[i][p] = arr;\n        }\n    }\n\n    auto can_pick_idx  = [&](int idx) -> bool { return idx >= 0 && isSur[idx]; };\n    auto can_place_idx = [&](int idx) -> bool { return idx >= 0 && isDef[idx]; };\n\n    auto has_any_target_dir = [&](int leafId, int rootPos) -> bool {\n        const Leaf &lf = leaves[leafId];\n        const auto &arr = endIdx[leafId][rootPos];\n        if (!lf.hold) {\n            return (arr[0] >= 0 && isSur[arr[0]]) || (arr[1] >= 0 && isSur[arr[1]]) ||\n                   (arr[2] >= 0 && isSur[arr[2]]) || (arr[3] >= 0 && isSur[arr[3]]);\n        } else {\n            return (arr[0] >= 0 && isDef[arr[0]]) || (arr[1] >= 0 && isDef[arr[1]]) ||\n                   (arr[2] >= 0 && isDef[arr[2]]) || (arr[3] >= 0 && isDef[arr[3]]);\n        }\n    };\n\n    auto can_act_immediately = [&](int leafId, int rootPos) -> bool {\n        const Leaf &lf = leaves[leafId];\n        int d0 = lf.dir;\n        int dL = (d0 + 3) & 3;\n        int dR = (d0 + 1) & 3;\n        const auto &arr = endIdx[leafId][rootPos];\n        if (!lf.hold) {\n            return can_pick_idx(arr[d0]) || can_pick_idx(arr[dL]) || can_pick_idx(arr[dR]);\n        } else {\n            return can_place_idx(arr[d0]) || can_place_idx(arr[dL]) || can_place_idx(arr[dR]);\n        }\n    };\n\n    auto decide_rot_and_action = [&](int leafId, int rootPos) -> pair<char,bool> {\n        const Leaf &lf = leaves[leafId];\n        int d0 = lf.dir;\n        int dL = (d0 + 3) & 3;\n        int dR = (d0 + 1) & 3;\n        const auto &arr = endIdx[leafId][rootPos];\n\n        // Immediate action: prefer '.' then 'L' then 'R'\n        if (!lf.hold) {\n            if (can_pick_idx(arr[d0])) return {'.', true};\n            if (can_pick_idx(arr[dL])) return {'L', true};\n            if (can_pick_idx(arr[dR])) return {'R', true};\n        } else {\n            if (can_place_idx(arr[d0])) return {'.', true};\n            if (can_place_idx(arr[dL])) return {'L', true};\n            if (can_place_idx(arr[dR])) return {'R', true};\n        }\n\n        // Prepare (one-step best effort): rotate toward any useful direction\n        int useful[4], ucnt = 0;\n        if (!lf.hold) {\n            for (int d = 0; d < 4; d++) if (can_pick_idx(arr[d])) useful[ucnt++] = d;\n        } else {\n            for (int d = 0; d < 4; d++) if (can_place_idx(arr[d])) useful[ucnt++] = d;\n        }\n        if (ucnt == 0) return {'.', false};\n\n        auto mindist = [&](int nd) -> int {\n            int best = 10;\n            for (int i = 0; i < ucnt; i++) best = min(best, ang_dist(nd, useful[i]));\n            return best;\n        };\n\n        int dist0 = mindist(d0);\n        int distL = mindist(dL);\n        int distR = mindist(dR);\n\n        if (dist0 <= distL && dist0 <= distR) return {'.', false};\n        if (distL <= distR) return {'L', false};\n        return {'R', false};\n    };\n\n    // initial root: centroid of mismatches\n    int rx = N / 2, ry = N / 2;\n    long long needCnt0 = surCount + defCount;\n    if (needCnt0 > 0) {\n        long long sumX = sumSurX + sumDefX;\n        long long sumY = sumSurY + sumDefY;\n        rx = (int)(sumX / needCnt0);\n        ry = (int)(sumY / needCnt0);\n        rx = min(max(rx, 0), N - 1);\n        ry = min(max(ry, 0), N - 1);\n    }\n    const int initRx = rx, initRy = ry;\n\n    // Move candidates\n    const char mvChar[5] = {'.','U','D','L','R'};\n    const int mvDx[5] = {0,-1,1,0,0};\n    const int mvDy[5] = {0,0,0,-1,1};\n\n    vector<string> ops;\n    ops.reserve(100000);\n\n    int noActStreak = 0;\n\n    // Phase control with hysteresis:\n    // phase=0 collect (prefer pick), phase=1 deliver (prefer place)\n    int phase = 0;\n    int holdCnt = 0;\n    int highTh = max(1, (2 * K) / 3);\n    int lowTh  = max(0, K / 3);\n\n    int targetRx = rx, targetRy = ry;\n    bool haveTarget = false;\n\n    // Dynamic scan interval to stay safe on time, but never early-stop.\n    int scanInterval = 30;\n    bool disableGlobalScan = false;\n\n    auto recompute_best_root_target = [&]() {\n        // Phase-aware scanning objective\n        // collect: emphasize potPick, deliver: emphasize potPlace\n        long long bestScore = LLONG_MIN;\n        int bestX = rx, bestY = ry;\n\n        for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n            int p = x * N + y;\n            int potPick = 0, potPlace = 0;\n            for (int i = 0; i < K; i++) {\n                if (!has_any_target_dir(i, p)) continue;\n                if (!leaves[i].hold) potPick++;\n                else potPlace++;\n            }\n            int dist = abs(rx - x) + abs(ry - y);\n\n            long long score;\n            if (phase == 0) {\n                // collect\n                score = 1200LL * potPick + 200LL * potPlace - 25LL * dist;\n            } else {\n                // deliver\n                score = 200LL * potPick + 1200LL * potPlace - 25LL * dist;\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                bestX = x; bestY = y;\n            }\n        }\n\n        targetRx = bestX;\n        targetRy = bestY;\n        haveTarget = true;\n    };\n\n    const int TURN_LIMIT = 100000;\n\n    for (int turn = 0; turn < TURN_LIMIT; turn++) {\n        if (surCount == 0 && defCount == 0) break;\n\n        // Update phase (hysteresis)\n        if (phase == 0) {\n            if (holdCnt >= highTh || surCount == 0) phase = 1;\n        } else {\n            if (holdCnt <= lowTh && surCount > 0) phase = 0;\n        }\n\n        // Coarse time-based degradation (checked rarely)\n        if ((turn & 511) == 0) {\n            double e = elapsed_sec();\n            if (e > 2.4) scanInterval = 120;\n            if (e > 2.75) disableGlobalScan = true;\n        }\n\n        // If already at target, allow refreshing sooner\n        if (haveTarget && rx == targetRx && ry == targetRy && noActStreak > 5) haveTarget = false;\n\n        if (!disableGlobalScan) {\n            if (!haveTarget || (turn % scanInterval == 0) || noActStreak > 25) {\n                recompute_best_root_target();\n            }\n        } else {\n            if (!haveTarget) {\n                long long needCnt = surCount + defCount;\n                if (needCnt > 0) {\n                    long long sx = sumSurX + sumDefX;\n                    long long sy = sumSurY + sumDefY;\n                    targetRx = (int)(sx / needCnt);\n                    targetRy = (int)(sy / needCnt);\n                    targetRx = min(max(targetRx, 0), N - 1);\n                    targetRy = min(max(targetRy, 0), N - 1);\n                } else {\n                    targetRx = rx; targetRy = ry;\n                }\n                haveTarget = true;\n            }\n        }\n\n        long long needCnt = surCount + defCount;\n        long long sumNeedX = sumSurX + sumDefX;\n        long long sumNeedY = sumSurY + sumDefY;\n\n        // Phase weights\n        int wPickImm, wPlaceImm, wPickPot, wPlacePot;\n        if (phase == 0) { // collect\n            wPickImm = 3; wPlaceImm = 1;\n            wPickPot = 3; wPlacePot = 1;\n        } else { // deliver\n            wPickImm = 1; wPlaceImm = 3;\n            wPickPot = 1; wPlacePot = 3;\n        }\n\n        auto eval_move = [&](int mv) -> long long {\n            int nrx = rx + mvDx[mv], nry = ry + mvDy[mv];\n            if (!inside(nrx, nry)) return LLONG_MIN / 4;\n            int np = nrx * N + nry;\n\n            int immPick = 0, immPlace = 0;\n            int potPick = 0, potPlace = 0;\n\n            for (int i = 0; i < K; i++) {\n                bool imm = can_act_immediately(i, np);\n                bool pot = has_any_target_dir(i, np);\n                if (!leaves[i].hold) {\n                    immPick += imm;\n                    potPick += pot;\n                } else {\n                    immPlace += imm;\n                    potPlace += pot;\n                }\n            }\n\n            int before = abs(rx - targetRx) + abs(ry - targetRy);\n            int after  = abs(nrx - targetRx) + abs(nry - targetRy);\n            int progress = before - after;\n\n            long long centroidDist = 0;\n            if (needCnt > 0) {\n                centroidDist =\n                    (llabs(1LL * nrx * needCnt - sumNeedX) + llabs(1LL * nry * needCnt - sumNeedY)) / needCnt;\n            }\n\n            long long immScore = 1LL * wPickImm * immPick + 1LL * wPlaceImm * immPlace;\n            long long potScore = 1LL * wPickPot * potPick + 1LL * wPlacePot * potPlace;\n\n            return 1000000LL * immScore + 2500LL * potScore + 30000LL * progress - 35LL * centroidDist;\n        };\n\n        int bestMove = 0;\n        long long bestScore = LLONG_MIN;\n        for (int mv = 0; mv < 5; mv++) {\n            long long sc = eval_move(mv);\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestMove = mv;\n            }\n        }\n\n        int nrx = rx + mvDx[bestMove], nry = ry + mvDy[bestMove];\n        if (!inside(nrx, nry)) { bestMove = 0; nrx = rx; nry = ry; }\n        int np = nrx * N + nry;\n\n        vector<char> rotCmd(K, '.');\n        vector<char> actCmd(K, '.');\n        for (int i = 0; i < K; i++) {\n            auto [rc, doP] = decide_rot_and_action(i, np);\n            rotCmd[i] = rc;\n            actCmd[i] = doP ? 'P' : '.';\n        }\n\n        string cmd(2 * Vp, '.');\n        cmd[0] = mvChar[bestMove];\n        for (int i = 0; i < K; i++) cmd[1 + i] = rotCmd[i];\n        cmd[Vp + 0] = '.';\n        for (int i = 0; i < K; i++) cmd[Vp + 1 + i] = actCmd[i];\n\n        // Apply move\n        rx = nrx; ry = nry;\n\n        // Apply rotations\n        for (int i = 0; i < K; i++) {\n            if (rotCmd[i] == 'L') leaves[i].dir = (leaves[i].dir + 3) & 3;\n            else if (rotCmd[i] == 'R') leaves[i].dir = (leaves[i].dir + 1) & 3;\n        }\n\n        // Apply actions in vertex order (1..K)\n        int executed = 0;\n        int rp = rx * N + ry;\n        for (int i = 0; i < K; i++) {\n            if (cmd[Vp + 1 + i] != 'P') continue;\n            int idx = endIdx[i][rp][leaves[i].dir];\n            bool ok = false;\n\n            if (!leaves[i].hold) {\n                if (idx >= 0 && isSur[idx]) {\n                    ok = true;\n                    leaves[i].hold = true;\n                    holdCnt++;\n                    isSur[idx] = 0;\n                    surCount--;\n                    int x = idx / N, y = idx % N;\n                    sumSurX -= x; sumSurY -= y;\n                }\n            } else {\n                if (idx >= 0 && isDef[idx]) {\n                    ok = true;\n                    leaves[i].hold = false;\n                    holdCnt--;\n                    isDef[idx] = 0;\n                    defCount--;\n                    int x = idx / N, y = idx % N;\n                    sumDefX -= x; sumDefY -= y;\n                }\n            }\n\n            if (!ok) {\n                cmd[Vp + 1 + i] = '.';\n            } else {\n                executed++;\n            }\n        }\n\n        ops.push_back(std::move(cmd));\n        noActStreak = (executed > 0) ? 0 : (noActStreak + 1);\n    }\n\n    // Output arm design\n    cout << Vp << \"\\n\";\n    for (int u = 1; u < Vp; u++) {\n        cout << 0 << \" \" << lengths[u - 1] << \"\\n\";\n    }\n    cout << initRx << \" \" << initRy << \"\\n\";\n\n    for (auto &c : ops) cout << c << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n};\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed = 0) { if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstatic constexpr int MAXC = 100000;\nstatic constexpr int G = 200;\nstatic constexpr int CELL = 500;\nstatic constexpr int PERIM_LIMIT_EDGES = 800;\n\nstruct Pt { int x, y, w; };\nstruct Rect { int x1, x2, y1, y2; };\n\nstatic inline long long rectPerimeter(const Rect& r) {\n    return 2LL * ((long long)r.x2 - r.x1 + (long long)r.y2 - r.y1);\n}\n\n// ---------------------- 2D BIT (Fenwick of vectors), static points ----------------------\nstruct BIT2D {\n    int nx = 0;\n    vector<int> xs;\n    vector<vector<int>> ys;\n    vector<vector<int>> bit;\n\n    static void add1D(vector<int>& b, int idx, int val) {\n        for (int i = idx; i < (int)b.size(); i += i & -i) b[i] += val;\n    }\n    static int sum1D(const vector<int>& b, int idx) {\n        int s = 0;\n        for (int i = idx; i > 0; i -= i & -i) s += b[i];\n        return s;\n    }\n\n    void build(const vector<Pt>& pts) {\n        xs.clear();\n        xs.reserve(pts.size());\n        for (auto &p : pts) xs.push_back(p.x);\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        nx = (int)xs.size();\n\n        ys.assign(nx + 1, {});\n        for (auto &p : pts) {\n            int xi = (int)(lower_bound(xs.begin(), xs.end(), p.x) - xs.begin()) + 1;\n            for (int x = xi; x <= nx; x += x & -x) ys[x].push_back(p.y);\n        }\n        bit.assign(nx + 1, {});\n        for (int x = 1; x <= nx; x++) {\n            auto &v = ys[x];\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n            bit[x].assign((int)v.size() + 1, 0);\n        }\n        for (auto &p : pts) addPoint(p.x, p.y, p.w);\n    }\n\n    void addPoint(int xval, int yval, int w) {\n        int xi = (int)(lower_bound(xs.begin(), xs.end(), xval) - xs.begin()) + 1;\n        for (int x = xi; x <= nx; x += x & -x) {\n            int yi = (int)(lower_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin()) + 1;\n            add1D(bit[x], yi, w);\n        }\n    }\n\n    int prefix(int xval, int yval) const {\n        int xi = (int)(upper_bound(xs.begin(), xs.end(), xval) - xs.begin());\n        int res = 0;\n        for (int x = xi; x > 0; x -= x & -x) {\n            int yi = (int)(upper_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin());\n            res += sum1D(bit[x], yi);\n        }\n        return res;\n    }\n\n    int rectSum(int x1, int x2, int y1, int y2) const {\n        if (x2 < x1 || y2 < y1) return 0;\n        int A = prefix(x2, y2);\n        int B = prefix(x1 - 1, y2);\n        int C = prefix(x2, y1 - 1);\n        int D = prefix(x1 - 1, y1 - 1);\n        return A - B - C + D;\n    }\n};\n\n// ---------------------- polygon evaluation ----------------------\nstatic inline bool onSegAxisAligned(int x, int y, int x1, int y1, int x2, int y2) {\n    if (x1 == x2) {\n        if (x != x1) return false;\n        if (y1 > y2) swap(y1, y2);\n        return y1 <= y && y <= y2;\n    } else if (y1 == y2) {\n        if (y != y1) return false;\n        if (x1 > x2) swap(x1, x2);\n        return x1 <= x && x <= x2;\n    }\n    return false;\n}\n\nstatic bool insidePolyInclusive(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (onSegAxisAligned(x, y, x1, y1, x2, y2)) return true;\n    }\n    bool in = false;\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (x1 == x2) {\n            int xv = x1;\n            int yl = min(y1, y2), yh = max(y1, y2);\n            if (yl < y && y <= yh) {\n                if (xv > x) in = !in;\n            }\n        }\n    }\n    return in;\n}\n\nstatic int evalPolygonDiff(const vector<Pt>& pts, const vector<pair<int,int>>& poly) {\n    int s = 0;\n    for (auto &p : pts) if (insidePolyInclusive(poly, p.x, p.y)) s += p.w;\n    return s;\n}\n\nstatic long long polygonPerimeter(const vector<pair<int,int>>& poly) {\n    long long per = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        per += llabs(x1-x2) + llabs(y1-y2);\n    }\n    return per;\n}\n\nstatic bool segIntersectAxis(const pair<int,int>& a, const pair<int,int>& b,\n                            const pair<int,int>& c, const pair<int,int>& d) {\n    int ax=a.first, ay=a.second, bx=b.first, by=b.second;\n    int cx=c.first, cy=c.second, dx=d.first, dy=d.second;\n    if (ay == by && cy == dy) {\n        if (ay != cy) return false;\n        if (ax > bx) swap(ax,bx);\n        if (cx > dx) swap(cx,dx);\n        return max(ax,cx) <= min(bx,dx);\n    }\n    if (ax == bx && cx == dx) {\n        if (ax != cx) return false;\n        if (ay > by) swap(ay,by);\n        if (cy > dy) swap(cy,dy);\n        return max(ay,cy) <= min(by,dy);\n    }\n    if (ay == by && cx == dx) {\n        if (ax > bx) swap(ax,bx);\n        if (cy > dy) swap(cy,dy);\n        return (ax <= cx && cx <= bx && cy <= ay && ay <= dy);\n    }\n    if (ax == bx && cy == dy) {\n        if (cx > dx) swap(cx,dx);\n        if (ay > by) swap(ay,by);\n        return (cx <= ax && ax <= dx && ay <= cy && cy <= by);\n    }\n    return false;\n}\n\nstatic bool isSimpleOrthogonal(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto a = poly[i];\n        auto b = poly[(i+1)%m];\n        for (int j = i+1; j < m; j++) {\n            if ((i+1)%m == j) continue;\n            if ((j+1)%m == i) continue;\n            auto c = poly[j];\n            auto d = poly[(j+1)%m];\n            if (segIntersectAxis(a,b,c,d)) return false;\n        }\n    }\n    return true;\n}\n\nstatic bool validOutput(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n    if (m < 4 || m > 1000) return false;\n    {\n        vector<pair<int,int>> tmp = poly;\n        sort(tmp.begin(), tmp.end());\n        if (unique(tmp.begin(), tmp.end()) != tmp.end()) return false;\n    }\n    for (auto [x,y] : poly) if (x < 0 || x > MAXC || y < 0 || y > MAXC) return false;\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        if (!(x1==x2 || y1==y2)) return false;\n        if (x1==x2 && y1==y2) return false;\n    }\n    if (polygonPerimeter(poly) > 400000) return false;\n    if (!isSimpleOrthogonal(poly)) return false;\n    return true;\n}\n\n// ---------------------- polyomino (grid) ----------------------\nstruct GridCfg {\n    int ox, oy;\n    int xmax, ymax;\n};\n\nstatic inline bool inAllowed(const GridCfg& cfg, int x, int y) {\n    return 0 <= x && x <= cfg.xmax && 0 <= y && y <= cfg.ymax;\n}\n\nstatic int computeBoundaryEdges(const vector<vector<unsigned char>>& occ) {\n    auto inside = [&](int x, int y)->bool{ return 0 <= x && x < G && 0 <= y && y < G; };\n    int edges = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) {\n        if (!inside(x-1,y) || !occ[y][x-1]) edges++;\n        if (!inside(x+1,y) || !occ[y][x+1]) edges++;\n        if (!inside(x,y-1) || !occ[y-1][x]) edges++;\n        if (!inside(x,y+1) || !occ[y+1][x]) edges++;\n    }\n    return edges;\n}\n\nstatic int computeTotalW(const vector<vector<unsigned char>>& occ, const vector<vector<int>>& wgrid) {\n    int s = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occ[y][x]) s += wgrid[y][x];\n    return s;\n}\n\nstatic void fillHoles(const GridCfg& cfg, vector<vector<unsigned char>>& occ) {\n    vector<vector<unsigned char>> vis(G, vector<unsigned char>(G, 0));\n    deque<pair<int,int>> dq;\n    auto pushIf = [&](int x, int y) {\n        if (!inAllowed(cfg,x,y)) return;\n        if (vis[y][x]) return;\n        if (occ[y][x]) return;\n        vis[y][x] = 1;\n        dq.push_back({x,y});\n    };\n    for (int x = 0; x <= cfg.xmax; x++) { pushIf(x,0); pushIf(x,cfg.ymax); }\n    for (int y = 0; y <= cfg.ymax; y++) { pushIf(0,y); pushIf(cfg.xmax,y); }\n\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n    while (!dq.empty()) {\n        auto [x,y] = dq.front(); dq.pop_front();\n        for (int k = 0; k < 4; k++) pushIf(x+dx4[k], y+dy4[k]);\n    }\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n        if (!occ[y][x] && !vis[y][x]) occ[y][x] = 1;\n    }\n}\n\nstatic void pruneNegativeLeaves(const GridCfg& cfg, vector<vector<unsigned char>>& occ, const vector<vector<int>>& wgrid) {\n    vector<vector<int>> deg(G, vector<int>(G, 0));\n    int cells = 0;\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (occ[y][x]) {\n        cells++;\n        int d = 0;\n        if (ok(x-1,y) && occ[y][x-1]) d++;\n        if (ok(x+1,y) && occ[y][x+1]) d++;\n        if (ok(x,y-1) && occ[y-1][x]) d++;\n        if (ok(x,y+1) && occ[y+1][x]) d++;\n        deg[y][x] = d;\n    }\n\n    deque<pair<int,int>> q;\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n        if (occ[y][x] && wgrid[y][x] < 0 && deg[y][x] <= 1) q.push_back({x,y});\n    }\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n    while (!q.empty()) {\n        auto [x,y] = q.front(); q.pop_front();\n        if (!occ[y][x]) continue;\n        if (wgrid[y][x] >= 0) continue;\n        if (deg[y][x] > 1) continue;\n        if (cells <= 1) break;\n        occ[y][x] = 0;\n        cells--;\n        for (int k = 0; k < 4; k++) {\n            int nx=x+dx4[k], ny=y+dy4[k];\n            if (!ok(nx,ny) || !occ[ny][nx]) continue;\n            deg[ny][nx]--;\n            if (wgrid[ny][nx] < 0 && deg[ny][nx] <= 1) q.push_back({nx,ny});\n        }\n    }\n}\n\nstruct Polyomino {\n    vector<vector<unsigned char>> occ;\n    int totalW = 0;\n    int boundaryEdges = 0;\n};\n\nstatic Polyomino greedyExpandPolyomino(const GridCfg& cfg,\n                                      const vector<vector<int>>& wgrid,\n                                      vector<vector<unsigned char>> occInit) {\n    Polyomino P;\n    P.occ = std::move(occInit);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n\n    vector<vector<unsigned char>> isCand(G, vector<unsigned char>(G, 0));\n    struct Node { int key; int x,y; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.key < b.key; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n    auto sharedCount = [&](int x, int y)->int{\n        int s = 0;\n        if (ok(x-1,y) && P.occ[y][x-1]) s++;\n        if (ok(x+1,y) && P.occ[y][x+1]) s++;\n        if (ok(x,y-1) && P.occ[y-1][x]) s++;\n        if (ok(x,y+1) && P.occ[y+1][x]) s++;\n        return s;\n    };\n    auto deltaEdgesAdd = [&](int x, int y)->int{\n        int sh = sharedCount(x,y);\n        return 4 - 2*sh;\n    };\n    auto keyOf = [&](int x, int y)->int{\n        int dw = wgrid[y][x];\n        int de = deltaEdgesAdd(x,y);\n        return dw * 1000 - de * 35;\n    };\n    auto pushCandidate = [&](int x, int y){\n        if (!ok(x,y)) return;\n        if (P.occ[y][x]) return;\n        if (isCand[y][x]) return;\n        isCand[y][x] = 1;\n        pq.push(Node{keyOf(x,y), x, y});\n    };\n\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (P.occ[y][x]) {\n        pushCandidate(x-1,y); pushCandidate(x+1,y); pushCandidate(x,y-1); pushCandidate(x,y+1);\n    }\n\n    while (!pq.empty()) {\n        auto nd = pq.top(); pq.pop();\n        int x = nd.x, y = nd.y;\n        if (!isCand[y][x]) continue;\n        if (P.occ[y][x]) { isCand[y][x] = 0; continue; }\n        int kNow = keyOf(x,y);\n        if (kNow != nd.key) { pq.push(Node{kNow,x,y}); continue; }\n\n        int dw = wgrid[y][x];\n        int de = deltaEdgesAdd(x,y);\n        if (P.boundaryEdges + de > PERIM_LIMIT_EDGES) { isCand[y][x] = 0; continue; }\n\n        bool accept = false;\n        if (dw > 0) accept = true;\n        else if (dw == 0 && de < 0) accept = true;\n        else if (dw >= -2 && de <= -2) accept = true;\n        if (!accept) { isCand[y][x] = 0; continue; }\n\n        P.occ[y][x] = 1;\n        isCand[y][x] = 0;\n        P.totalW += dw;\n        P.boundaryEdges += de;\n\n        pushCandidate(x-1,y); pushCandidate(x+1,y); pushCandidate(x,y-1); pushCandidate(x,y+1);\n        if (P.boundaryEdges >= PERIM_LIMIT_EDGES) break;\n    }\n\n    fillHoles(cfg, P.occ);\n    pruneNegativeLeaves(cfg, P.occ, wgrid);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n    return P;\n}\n\nstatic void localImprovePolyomino(Polyomino& P, const GridCfg& cfg, const vector<vector<int>>& wgrid,\n                                 XorShift& rng, double timeEnd,\n                                 function<double()> elapsedSec) {\n    vector<int> occVec;\n    vector<int> pos(G*G, -1);\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (P.occ[y][x]) {\n        int id = y*G + x;\n        pos[id] = (int)occVec.size();\n        occVec.push_back(id);\n    }\n    if (occVec.empty()) return;\n\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n\n    vector<int> vis(G*G, 0);\n    int stamp = 1;\n\n    auto countNeighbors = [&](int x, int y)->int{\n        int s=0;\n        if (ok(x-1,y) && P.occ[y][x-1]) s++;\n        if (ok(x+1,y) && P.occ[y][x+1]) s++;\n        if (ok(x,y-1) && P.occ[y-1][x]) s++;\n        if (ok(x,y+1) && P.occ[y+1][x]) s++;\n        return s;\n    };\n\n    auto connectedAfterRemoval = [&](int rx, int ry)->bool{\n        int cells = (int)occVec.size();\n        if (cells <= 1) return false;\n        int rid = ry*G + rx;\n        int startId = -1;\n        for (int id : occVec) if (id != rid) { startId = id; break; }\n        if (startId < 0) return true;\n\n        stamp++;\n        deque<int> dq;\n        dq.push_back(startId);\n        vis[startId] = stamp;\n        int cnt = 0;\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            cnt++;\n            int x = v % G, y = v / G;\n            for (int k = 0; k < 4; k++) {\n                int nx = x + dx4[k], ny = y + dy4[k];\n                if (!ok(nx,ny)) continue;\n                int nid = ny*G + nx;\n                if (vis[nid] == stamp) continue;\n                if (!P.occ[ny][nx]) continue;\n                vis[nid] = stamp;\n                dq.push_back(nid);\n            }\n        }\n        return cnt == cells - 1;\n    };\n\n    while (elapsedSec() < timeEnd) {\n        bool doAdd = (rng.nextInt(0, 99) < 58);\n        if (doAdd) {\n            int base = occVec[rng.nextInt(0, (int)occVec.size()-1)];\n            int bx = base % G, by = base / G;\n            int k = rng.nextInt(0, 3);\n            int nx = bx + dx4[k], ny = by + dy4[k];\n            if (!ok(nx,ny)) continue;\n            if (P.occ[ny][nx]) continue;\n\n            int sh = countNeighbors(nx, ny);\n            int de = 4 - 2*sh;\n            if (P.boundaryEdges + de > PERIM_LIMIT_EDGES) continue;\n\n            int dw = wgrid[ny][nx];\n            bool accept = false;\n            if (dw > 0) accept = true;\n            else if (dw == 0 && de <= 0) accept = true;\n            else if (dw >= -1 && de <= -2) accept = true;\n            else if (dw >= -3 && de <= -4) accept = true;\n            if (!accept) continue;\n\n            P.occ[ny][nx] = 1;\n            int id = ny*G + nx;\n            pos[id] = (int)occVec.size();\n            occVec.push_back(id);\n            P.totalW += dw;\n            P.boundaryEdges += de;\n        } else {\n            if ((int)occVec.size() <= 1) continue;\n            int id = occVec[rng.nextInt(0, (int)occVec.size()-1)];\n            int x = id % G, y = id / G;\n            int dw = wgrid[y][x];\n            if (dw >= 0) continue;\n\n            int sh = countNeighbors(x, y);\n            if (sh == 0) continue;\n            int deRemove = -(4 - 2*sh);\n            if (P.boundaryEdges + deRemove > PERIM_LIMIT_EDGES) continue;\n\n            P.occ[y][x] = 0;\n            bool okc = connectedAfterRemoval(x, y);\n            if (!okc) {\n                P.occ[y][x] = 1;\n                continue;\n            }\n            int idx = pos[id];\n            int last = occVec.back();\n            occVec[idx] = last;\n            pos[last] = idx;\n            occVec.pop_back();\n            pos[id] = -1;\n\n            P.totalW -= dw;\n            P.boundaryEdges += deRemove;\n        }\n    }\n\n    fillHoles(cfg, P.occ);\n    pruneNegativeLeaves(cfg, P.occ, wgrid);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n}\n\n// compress collinear cyclic\nstatic bool collinearAxis(const pair<int,int>& a, const pair<int,int>& b, const pair<int,int>& c) {\n    return (a.first == b.first && b.first == c.first) || (a.second == b.second && b.second == c.second);\n}\nstatic vector<pair<int,int>> compressCollinearCyclic(vector<pair<int,int>> v) {\n    vector<pair<int,int>> w;\n    for (auto &p : v) if (w.empty() || w.back() != p) w.push_back(p);\n    v.swap(w);\n    if (v.size() >= 2 && v.front() == v.back()) v.pop_back();\n\n    bool changed = true;\n    while (changed && v.size() >= 4) {\n        changed = false;\n        int n = (int)v.size();\n        vector<char> del(n, 0);\n        for (int i = 0; i < n; i++) {\n            int ip = (i - 1 + n) % n;\n            int in = (i + 1) % n;\n            if (collinearAxis(v[ip], v[i], v[in])) del[i] = 1;\n        }\n        int cnt = 0;\n        for (int i = 0; i < n; i++) if (!del[i]) cnt++;\n        if (cnt < n && cnt >= 4) {\n            vector<pair<int,int>> nv;\n            nv.reserve(cnt);\n            for (int i = 0; i < n; i++) if (!del[i]) nv.push_back(v[i]);\n            v.swap(nv);\n            changed = true;\n        }\n    }\n    return v;\n}\n\n// boundary extraction from occ using directed CCW edges (interior on left)\nstatic bool extractBoundaryPolygon(const GridCfg& cfg, const vector<vector<unsigned char>>& occ, vector<pair<int,int>>& outPoly) {\n    const int W = G + 1;\n    const int V = W * W;\n    auto vid = [&](int x, int y)->int{ return y * W + x; };\n    auto vxy = [&](int id)->pair<int,int>{ return {id % W, id / W}; };\n\n    vector<int> nxt(V, -1);\n    vector<char> hasOut(V, 0);\n    bool conflict = false;\n\n    auto cellOcc = [&](int x, int y)->bool{\n        if (!inAllowed(cfg,x,y)) return false;\n        return occ[y][x] != 0;\n    };\n    auto addEdge = [&](int x1,int y1,int x2,int y2){\n        int a = vid(x1,y1), b = vid(x2,y2);\n        if (nxt[a] == -1) { nxt[a] = b; hasOut[a] = 1; }\n        else if (nxt[a] != b) conflict = true;\n    };\n\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (occ[y][x]) {\n        if (!cellOcc(x, y-1)) addEdge(x, y, x+1, y);\n        if (!cellOcc(x+1, y)) addEdge(x+1, y, x+1, y+1);\n        if (!cellOcc(x, y+1)) addEdge(x+1, y+1, x, y+1);\n        if (!cellOcc(x-1, y)) addEdge(x, y+1, x, y);\n    }\n    if (conflict) return false;\n\n    int start = -1;\n    for (int id = 0; id < V; id++) if (hasOut[id]) {\n        if (start == -1) start = id;\n        else {\n            auto [x1,y1] = vxy(id);\n            auto [x0,y0] = vxy(start);\n            if (y1 < y0 || (y1 == y0 && x1 < x0)) start = id;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<pair<int,int>> gridPath;\n    gridPath.reserve(4000);\n    int cur = start;\n    for (int steps = 0; steps < 500000; steps++) {\n        gridPath.push_back(vxy(cur));\n        int to = nxt[cur];\n        if (to == -1) break;\n        cur = to;\n        if (cur == start) break;\n    }\n    if (gridPath.size() < 4) return false;\n\n    vector<pair<int,int>> poly;\n    poly.reserve(gridPath.size());\n    for (auto [gx,gy] : gridPath) {\n        long long X = (long long)cfg.ox + (long long)gx * CELL;\n        long long Y = (long long)cfg.oy + (long long)gy * CELL;\n        if (X < 0 || X > MAXC || Y < 0 || Y > MAXC) return false;\n        poly.push_back({(int)X, (int)Y});\n    }\n    poly = compressCollinearCyclic(poly);\n    outPoly.swap(poly);\n    return true;\n}\n\n// ---------------------- grid building and max sub-rectangle ----------------------\nstatic void buildWGrid(const GridCfg& cfg, const vector<Pt>& pts, vector<vector<int>>& wgrid) {\n    for (int y = 0; y < G; y++) fill(wgrid[y].begin(), wgrid[y].end(), 0);\n    for (auto &p : pts) {\n        int rx = p.x - cfg.ox;\n        int ry = p.y - cfg.oy;\n        if (rx < 0 || ry < 0) continue;\n        int gx = rx / CELL;\n        int gy = ry / CELL;\n        if (!inAllowed(cfg, gx, gy)) continue;\n        wgrid[gy][gx] += p.w;\n    }\n}\n\nstatic tuple<int,int,int,int,int> maxSumSubRect(const GridCfg& cfg, const vector<vector<int>>& wgrid) {\n    int W = cfg.xmax + 1;\n    int H = cfg.ymax + 1;\n    int bestSum = INT_MIN;\n    int bestL=0,bestR=0,bestB=0,bestT=0;\n    vector<int> colSum(H);\n    for (int L = 0; L < W; L++) {\n        fill(colSum.begin(), colSum.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) colSum[y] += wgrid[y][R];\n            int cur = 0, curStart = 0;\n            int localBest = INT_MIN, localB = 0, localT = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) { cur = colSum[y]; curStart = y; }\n                else cur += colSum[y];\n                if (cur > localBest) { localBest = cur; localB = curStart; localT = y; }\n            }\n            if (localBest > bestSum) {\n                bestSum = localBest;\n                bestL=L; bestR=R; bestB=localB; bestT=localT;\n            }\n        }\n    }\n    return {bestSum,bestL,bestR,bestB,bestT};\n}\n\n// Best-sum shortest (monotone) path DP between two cells, and optionally reconstruct.\nstatic int bestShortestPathWeightDP(const GridCfg& cfg, const vector<vector<int>>& wgrid,\n                                   int x1,int y1,int x2,int y2, bool reconstruct,\n                                   vector<pair<int,int>>* outCells) {\n    if (!inAllowed(cfg,x1,y1) || !inAllowed(cfg,x2,y2)) return INT_MIN/4;\n    int sx = (x2 >= x1 ? 1 : -1);\n    int sy = (y2 >= y1 ? 1 : -1);\n    int ax = abs(x2 - x1);\n    int ay = abs(y2 - y1);\n    int W = ax + 1;\n    int H = ay + 1;\n    const int NEG = -1e9;\n\n    vector<int> dp(W*H, NEG);\n    vector<unsigned char> pre; // 0 from left, 1 from up\n    if (reconstruct) pre.assign(W*H, 0);\n\n    auto idx = [&](int i,int j){ return j*W + i; };\n    auto cell = [&](int i,int j)->pair<int,int>{\n        return {x1 + i*sx, y1 + j*sy};\n    };\n\n    dp[idx(0,0)] = wgrid[y1][x1];\n\n    for (int j = 0; j < H; j++) {\n        for (int i = 0; i < W; i++) {\n            if (i==0 && j==0) continue;\n            int best = NEG;\n            unsigned char p = 0;\n            if (i > 0 && dp[idx(i-1,j)] > best) { best = dp[idx(i-1,j)]; p = 0; }\n            if (j > 0 && dp[idx(i,j-1)] > best) { best = dp[idx(i,j-1)]; p = 1; }\n            auto [cx,cy] = cell(i,j);\n            if (!inAllowed(cfg,cx,cy)) continue;\n            dp[idx(i,j)] = best + wgrid[cy][cx];\n            if (reconstruct) pre[idx(i,j)] = p;\n        }\n    }\n\n    int res = dp[idx(ax,ay)];\n    if (!reconstruct || !outCells) return res;\n\n    outCells->clear();\n    outCells->reserve(ax + ay + 1);\n    int i = ax, j = ay;\n    while (!(i==0 && j==0)) {\n        auto [cx,cy] = cell(i,j);\n        outCells->push_back({cx,cy});\n        unsigned char p = pre[idx(i,j)];\n        if (p == 0) i--;\n        else j--;\n    }\n    outCells->push_back({x1,y1});\n    reverse(outCells->begin(), outCells->end());\n    return res;\n}\n\nstatic bool containsAnyRect(const vector<Pt>& pts, const Rect& r) {\n    for (auto &p : pts) if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) return true;\n    return false;\n}\n\nstruct CandPoly {\n    int approx;\n    vector<pair<int,int>> poly;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n\n    // deterministic RNG seed from input\n    SplitMix64 sm(123456789);\n    uint64_t hseed = 0;\n    for (int i = 0; i < 2*N; i++) {\n        int x,y; cin >> x >> y;\n        int w = (i < N ? +1 : -1);\n        pts.push_back(Pt{x,y,w});\n        uint64_t v = ((uint64_t)(uint32_t)x << 32) ^ (uint64_t)(uint32_t)y ^ (uint64_t)(w + 7);\n        sm.x ^= v + 0x9e3779b97f4a7c15ULL;\n        hseed ^= sm.next();\n    }\n    XorShift rng(hseed);\n\n    auto startTime = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]()->double{\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - startTime).count();\n    };\n\n    // Rectangle SA prep\n    BIT2D bit2d;\n    bit2d.build(pts);\n    auto evalRectFast = [&](const Rect& r)->int{\n        return bit2d.rectSum(r.x1, r.x2, r.y1, r.y2);\n    };\n\n    vector<int> candX, candY;\n    candX.reserve(30000);\n    candY.reserve(30000);\n    auto addCand = [&](vector<int>& v, int c){ if (0 <= c && c <= MAXC) v.push_back(c); };\n    addCand(candX, 0); addCand(candX, MAXC);\n    addCand(candY, 0); addCand(candY, MAXC);\n    for (int i = 0; i <= G; i++) { addCand(candX, i*CELL); addCand(candY, i*CELL); }\n    for (int i = 0; i < (int)pts.size(); i += 2) {\n        addCand(candX, pts[i].x); addCand(candX, pts[i].x-1); addCand(candX, pts[i].x+1);\n        addCand(candY, pts[i].y); addCand(candY, pts[i].y-1); addCand(candY, pts[i].y+1);\n    }\n    sort(candX.begin(), candX.end());\n    candX.erase(unique(candX.begin(), candX.end()), candX.end());\n    sort(candY.begin(), candY.end());\n    candY.erase(unique(candY.begin(), candY.end()), candY.end());\n\n    auto clampi = [&](int v){ return max(0, min(MAXC, v)); };\n\n    // Rectangle SA\n    Rect bestRect{0, MAXC, 0, MAXC};\n    int bestRectDiff = evalRectFast(bestRect);\n\n    auto randomRectAround = [&]()->Rect{\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size()-1)];\n        int wx = rng.nextInt(500, 25000);\n        int wy = rng.nextInt(500, 25000);\n        int x1 = clampi(p.x - wx), x2 = clampi(p.x + wx);\n        int y1 = clampi(p.y - wy), y2 = clampi(p.y + wy);\n        if (x2 <= x1) x2 = min(MAXC, x1+1);\n        if (y2 <= y1) y2 = min(MAXC, y1+1);\n        return Rect{x1,x2,y1,y2};\n    };\n\n    const double SA_TIME = 0.85;\n    const double T0 = 26.0, T1 = 0.9;\n    vector<Rect> starts;\n    for (int i = 0; i < 12; i++) starts.push_back(randomRectAround());\n    starts.push_back(bestRect);\n\n    for (auto st : starts) {\n        if (elapsedSec() > SA_TIME) break;\n        if (rectPerimeter(st) > 400000) continue;\n        Rect cur = st;\n        int curDiff = evalRectFast(cur);\n        while (elapsedSec() < SA_TIME) {\n            double t = elapsedSec() / SA_TIME;\n            double T = T0 * pow(T1 / T0, t);\n            Rect nxt = cur;\n            int side = rng.nextInt(0,3);\n            if (side == 0) {\n                int nx1 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx1 >= nxt.x2) continue;\n                nxt.x1 = nx1;\n            } else if (side == 1) {\n                int nx2 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx2 <= nxt.x1) continue;\n                nxt.x2 = nx2;\n            } else if (side == 2) {\n                int ny1 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny1 >= nxt.y2) continue;\n                nxt.y1 = ny1;\n            } else {\n                int ny2 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny2 <= nxt.y1) continue;\n                nxt.y2 = ny2;\n            }\n            if (rectPerimeter(nxt) > 400000) continue;\n            int nd = evalRectFast(nxt);\n            int delta = nd - curDiff;\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double prob = exp((double)delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n            if (accept) {\n                cur = nxt;\n                curDiff = nd;\n                if (curDiff > bestRectDiff) { bestRectDiff = curDiff; bestRect = cur; }\n            }\n        }\n    }\n\n    vector<pair<int,int>> bestPoly = {\n        {bestRect.x1, bestRect.y1},\n        {bestRect.x2, bestRect.y1},\n        {bestRect.x2, bestRect.y2},\n        {bestRect.x1, bestRect.y2}\n    };\n    int bestDiff = bestRectDiff;\n\n    // Polyomino candidates (approx ranked)\n    vector<CandPoly> candPolys;\n    auto pushCandPoly = [&](int approx, vector<pair<int,int>> poly){\n        if ((int)poly.size() < 4 || (int)poly.size() > 1000) return;\n        if (polygonPerimeter(poly) > 400000) return;\n        candPolys.push_back(CandPoly{approx, std::move(poly)});\n    };\n\n    // Grid configs (shifted)\n    vector<GridCfg> cfgs;\n    cfgs.push_back(GridCfg{0,   0,   199,199});\n    cfgs.push_back(GridCfg{250, 0,   198,199});\n    cfgs.push_back(GridCfg{0,   250, 199,198});\n    cfgs.push_back(GridCfg{250, 250, 198,198});\n\n    vector<vector<int>> wgrid(G, vector<int>(G, 0));\n    vector<vector<unsigned char>> occTmp(G, vector<unsigned char>(G, 0));\n    vector<pair<int,int>> pathCells;\n\n    const double GLOBAL_END = 1.93;\n\n    for (const auto& cfg : cfgs) {\n        if (elapsedSec() > GLOBAL_END) break;\n\n        buildWGrid(cfg, pts, wgrid);\n        auto [sumBest, L, R, B, T] = maxSumSubRect(cfg, wgrid);\n\n        // top K cells\n        vector<tuple<int,int,int>> cells;\n        cells.reserve((cfg.xmax+1)*(cfg.ymax+1));\n        for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n            cells.emplace_back(wgrid[y][x], x, y);\n        }\n        sort(cells.begin(), cells.end(), greater<>());\n        int K = min(12, (int)cells.size());\n        vector<pair<int,int>> topCells;\n        for (int i = 0; i < K; i++) {\n            auto [w,x,y] = cells[i];\n            if (w <= 0) break;\n            topCells.push_back({x,y});\n        }\n\n        auto runOccCandidate = [&](vector<vector<unsigned char>> occSeed, double localBudget){\n            if (elapsedSec() > GLOBAL_END) return;\n            Polyomino P = greedyExpandPolyomino(cfg, wgrid, std::move(occSeed));\n            if (P.boundaryEdges > PERIM_LIMIT_EDGES) return;\n\n            double localEnd = min(GLOBAL_END, elapsedSec() + localBudget);\n            localImprovePolyomino(P, cfg, wgrid, rng, localEnd, elapsedSec);\n\n            vector<pair<int,int>> poly;\n            if (!extractBoundaryPolygon(cfg, P.occ, poly)) return;\n            pushCandPoly(P.totalW, std::move(poly));\n        };\n\n        // A) best max-sum rectangle seed\n        {\n            for (int y = 0; y < G; y++) fill(occTmp[y].begin(), occTmp[y].end(), 0);\n            for (int y = B; y <= T; y++) for (int x = L; x <= R; x++) occTmp[y][x] = 1;\n            runOccCandidate(occTmp, 0.05);\n        }\n\n        // B) best single cell seed\n        {\n            int bx = 0, by = 0, bestW = INT_MIN;\n            for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n                if (wgrid[y][x] > bestW) { bestW = wgrid[y][x]; bx=x; by=y; }\n            }\n            if (bestW > 0 || sumBest > 0) {\n                for (int y = 0; y < G; y++) fill(occTmp[y].begin(), occTmp[y].end(), 0);\n                occTmp[by][bx] = 1;\n                runOccCandidate(occTmp, 0.04);\n            }\n        }\n\n        // C) best-sum shortest-path corridor pair seeds (DP)\n        if (topCells.size() >= 2) {\n            struct PairCand { int score; int i,j; int w; int dist; };\n            vector<PairCand> pairs;\n            int M = (int)topCells.size();\n            pairs.reserve(M*M);\n\n            for (int i = 0; i < M; i++) for (int j = i+1; j < M; j++) {\n                int x1=topCells[i].first, y1=topCells[i].second;\n                int x2=topCells[j].first, y2=topCells[j].second;\n                int dist = abs(x1-x2) + abs(y1-y2);\n                // compute best weight among all shortest paths\n                int w = bestShortestPathWeightDP(cfg, wgrid, x1,y1,x2,y2, false, nullptr);\n                if (w < -1000000) continue;\n                // heuristic: prefer good corridor weight and not too far\n                int score = w * 120 - dist * 70;\n                pairs.push_back({score,i,j,w,dist});\n            }\n            sort(pairs.begin(), pairs.end(), [](const PairCand& a, const PairCand& b){ return a.score > b.score; });\n\n            int TRY = min(4, (int)pairs.size());\n            for (int t = 0; t < TRY; t++) {\n                if (elapsedSec() > GLOBAL_END) break;\n                auto pc = pairs[t];\n                // skip very negative corridors\n                if (pc.w < 4) continue;\n\n                int x1=topCells[pc.i].first, y1=topCells[pc.i].second;\n                int x2=topCells[pc.j].first, y2=topCells[pc.j].second;\n\n                bestShortestPathWeightDP(cfg, wgrid, x1,y1,x2,y2, true, &pathCells);\n\n                for (int y = 0; y < G; y++) fill(occTmp[y].begin(), occTmp[y].end(), 0);\n                for (auto [cx,cy] : pathCells) occTmp[cy][cx] = 1;\n\n                runOccCandidate(occTmp, 0.03);\n            }\n        }\n    }\n\n    auto considerPoly = [&](const vector<pair<int,int>>& poly){\n        if (!validOutput(poly)) return;\n        int d = evalPolygonDiff(pts, poly);\n        if (d > bestDiff) { bestDiff = d; bestPoly = poly; }\n    };\n\n    sort(candPolys.begin(), candPolys.end(), [](const CandPoly& a, const CandPoly& b){\n        return a.approx > b.approx;\n    });\n    if ((int)candPolys.size() > 12) candPolys.resize(12);\n\n    for (auto &c : candPolys) {\n        if (elapsedSec() > 1.98) break;\n        considerPoly(c.poly);\n    }\n\n    // If bestDiff < 0, output an empty tiny rectangle for score 1\n    if (bestDiff < 0) {\n        Rect empty{0,1,0,1};\n        for (int tries = 0; tries < 5000; tries++) {\n            int x1 = rng.nextInt(0, MAXC-1);\n            int y1 = rng.nextInt(0, MAXC-1);\n            Rect r{x1, x1+1, y1, y1+1};\n            if (!containsAnyRect(pts, r)) { empty = r; break; }\n        }\n        bestPoly = {{empty.x1,empty.y1},{empty.x2,empty.y1},{empty.x2,empty.y2},{empty.x1,empty.y2}};\n    }\n\n    if (!validOutput(bestPoly)) {\n        bestPoly = {{0,0},{MAXC,0},{MAXC,MAXC},{0,MAXC}};\n    }\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto [x,y] : bestPoly) cout << x << \" \" << y << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Plan {\n    vector<Op> ops;\n    long long predW = (1LL<<62);\n    long long predH = (1LL<<62);\n    long long predScore = (1LL<<62);\n    string tag;\n};\n\nstatic inline pair<long long,long long> dims(const vector<long long>& w, const vector<long long>& h, int i, int r){\n    if(r==0) return {w[i], h[i]};\n    return {h[i], w[i]};\n}\n\nstatic inline int rot_wide_minheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=max(w,h) and height=min(w,h)\n    return (w[i] < h[i]) ? 1 : 0;\n}\nstatic inline int rot_narrow_maxheight(const vector<long long>& w, const vector<long long>& h, int i){\n    // choose rotation making width=min(w,h) and height=max(w,h)\n    return (w[i] > h[i]) ? 1 : 0;\n}\n\nPlan make_single_row(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r = (rotMode==0 ? rot_wide_minheight(w,h,i) : rot_narrow_maxheight(w,h,i));\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'L',-1});\n        W += ww;\n        H = max(H, hh);\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_row_wide\" : \"single_row_narrow\");\n    return pl;\n}\n\nPlan make_single_col(const vector<long long>& w, const vector<long long>& h, int rotMode){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r;\n        if(rotMode==0){\n            // minimize width\n            r = (w[i] > h[i]) ? 1 : 0;\n        }else{\n            // minimize height (often worse for columns but add diversity)\n            r = (w[i] < h[i]) ? 1 : 0;\n        }\n        auto [ww,hh] = dims(w,h,i,r);\n        pl.ops.push_back({i,r,'U',-1});\n        W = max(W, ww);\n        H += hh;\n    }\n    pl.predW=W; pl.predH=H; pl.predScore=W+H;\n    pl.tag = (rotMode==0 ? \"single_col_minW\" : \"single_col_minH\");\n    return pl;\n}\n\n// Contiguous shelf rows with width limit M (simple fallback/diversity).\nPlan make_shelf_rows_width_limit(const vector<long long>& w, const vector<long long>& h, long long M){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n\n    long long totalH = 0;\n    long long maxW = 0;\n\n    int prevRowRep = -1;\n    long long curW = 0;\n    long long curH = 0;\n    int curRep = -1;\n\n    auto close_row = [&](){\n        if(curRep==-1) return;\n        totalH += curH;\n        maxW = max(maxW, curW);\n        prevRowRep = curRep;\n        curW = 0;\n        curH = 0;\n        curRep = -1;\n    };\n\n    for(int i=0;i<N;i++){\n        // try both rotations\n        auto [w0,h0] = dims(w,h,i,0);\n        auto [w1,h1] = dims(w,h,i,1);\n        bool fit0 = (curRep==-1 ? (w0<=M || curW==0) : (curW + w0 <= M));\n        bool fit1 = (curRep==-1 ? (w1<=M || curW==0) : (curW + w1 <= M));\n\n        int r = -1;\n        if(curRep==-1){\n            // new row: choose smaller height\n            if(h0 < h1) r=0; else r=1;\n        }else{\n            if(fit0 && fit1){\n                // choose smaller resulting row height, tie by smaller width\n                long long nh0 = max(curH, h0), nh1 = max(curH, h1);\n                if(nh0 != nh1) r = (nh0 < nh1 ? 0 : 1);\n                else r = (w0 < w1 ? 0 : 1);\n            }else if(fit0) r=0;\n            else if(fit1) r=1;\n        }\n\n        if(curRep!=-1 && r==-1){\n            close_row();\n            // new row, pick smaller height\n            if(h0 < h1) r=0; else r=1;\n        }\n\n        auto [ww,hh] = dims(w,h,i,r);\n        int b = (prevRowRep==-1 ? -1 : prevRowRep);\n        pl.ops.push_back({i,r,'L',b});\n        curW += ww;\n        if(hh > curH){\n            curH = hh;\n            curRep = i;\n        }else if(curRep==-1){\n            curRep = i;\n        }\n    }\n    close_row();\n\n    pl.predW = maxW;\n    pl.predH = totalH;\n    pl.predScore = pl.predW + pl.predH;\n    pl.tag = \"shelf_rows_M=\" + to_string(M);\n    return pl;\n}\n\n// Fixed prefix headers 0..m-1 in top row, then greedy assign remaining to columns.\n// Requires each assigned rectangle width <= its column width, otherwise infeasible.\nPlan make_prefix_columns_bruteforce(const vector<long long>& w, const vector<long long>& h, int m){\n    int N = (int)w.size();\n    Plan best;\n    best.predScore = (1LL<<62);\n    if(m<=0 || m> N) return best;\n\n    int lim = 1<<m;\n    vector<int> bestHeaderRot(m,0);\n    vector<int> bestCol(N,-1), bestRot(N,0);\n\n    for(int mask=0; mask<lim; mask++){\n        vector<long long> colW(m), colH(m);\n        long long totalW = 0;\n        long long maxH = 0;\n        for(int j=0;j<m;j++){\n            int r = (mask>>j)&1;\n            auto [ww,hh] = dims(w,h,j,r);\n            colW[j]=ww; colH[j]=hh;\n            totalW += ww;\n            maxH = max(maxH, hh);\n        }\n\n        vector<int> colOf(N,-1), rotOf(N,0);\n        for(int j=0;j<m;j++){\n            colOf[j]=j;\n            rotOf[j]= (mask>>j)&1;\n        }\n\n        bool ok = true;\n        for(int i=m;i<N;i++){\n            long long bestObj = (1LL<<62);\n            int bestJ=-1, bestR=0;\n            for(int j=0;j<m;j++){\n                for(int r=0;r<=1;r++){\n                    auto [ww,hh] = dims(w,h,i,r);\n                    if(ww > colW[j]) continue;\n                    long long nh = colH[j] + hh;\n                    long long nMaxH = max(maxH, nh);\n                    long long obj = totalW + nMaxH;\n                    if(obj < bestObj || (obj==bestObj && nh < colH[bestJ] + dims(w,h,i,bestR).second)){\n                        bestObj=obj;\n                        bestJ=j; bestR=r;\n                    }\n                }\n            }\n            if(bestJ==-1){\n                ok=false; break;\n            }\n            auto [ww,hh] = dims(w,h,i,bestR);\n            colH[bestJ] += hh;\n            maxH = max(maxH, colH[bestJ]);\n            colOf[i]=bestJ;\n            rotOf[i]=bestR;\n        }\n        if(!ok) continue;\n\n        long long score = totalW + maxH;\n        if(score < best.predScore){\n            best.predScore = score;\n            best.predW = totalW;\n            best.predH = maxH;\n            best.ops.clear();\n            best.ops.reserve(N);\n\n            // build operations: headers L, others U with b = header of left column\n            // column j starts at right edge of header (j-1) (or x=0 if j=0)\n            for(int i=0;i<N;i++){\n                int r = rotOf[i];\n                if(i < m){\n                    best.ops.push_back({i,r,'L',-1});\n                }else{\n                    int cj = colOf[i];\n                    int b = (cj==0 ? -1 : (cj-1)); // header index (cj-1) because headers are 0..m-1\n                    best.ops.push_back({i,r,'U',b});\n                }\n            }\n            best.tag = \"prefix_cols_bruteforce_m=\" + to_string(m);\n        }\n    }\n    return best;\n}\n\n// Online columns: open new columns as needed/beneficial. Columns are disjoint by enforcing width<=colWidth.\nPlan make_online_columns(const vector<long long>& w, const vector<long long>& h,\n                         long long openBias, int headerMode, std::mt19937_64* rng = nullptr)\n{\n    int N = (int)w.size();\n    struct Col{ long long W,H; int headerIdx; };\n    vector<Col> cols;\n    vector<Op> ops;\n    ops.reserve(N);\n\n    long long totalW = 0;\n    long long maxH = 0;\n\n    auto chooseHeaderRot = [&](int i)->int{\n        if(headerMode==0) return rot_wide_minheight(w,h,i);\n        else return rot_narrow_maxheight(w,h,i);\n    };\n\n    for(int i=0;i<N;i++){\n        if(cols.empty()){\n            int r = chooseHeaderRot(i);\n            auto [ww,hh] = dims(w,h,i,r);\n            cols.push_back({ww,hh,i});\n            totalW += ww;\n            maxH = max(maxH, hh);\n            ops.push_back({i,r,'L',-1});\n            continue;\n        }\n\n        // best existing placement\n        long long bestObj = (1LL<<62);\n        int bestC = -1, bestR = 0;\n        for(int c=0;c<(int)cols.size();c++){\n            for(int r=0;r<=1;r++){\n                auto [ww,hh] = dims(w,h,i,r);\n                if(ww > cols[c].W) continue;\n                long long nh = cols[c].H + hh;\n                long long nMaxH = max(maxH, nh);\n                long long obj = totalW + nMaxH;\n                if(obj < bestObj){\n                    bestObj = obj;\n                    bestC = c;\n                    bestR = r;\n                }else if(obj == bestObj && rng){\n                    // random tie-break to diversify\n                    if(((*rng)() & 7ULL)==0ULL){\n                        bestC = c;\n                        bestR = r;\n                    }\n                }\n            }\n        }\n\n        // open new column option (always feasible)\n        int hr = chooseHeaderRot(i);\n        auto [wNew,hNew] = dims(w,h,i,hr);\n        long long openObj = (totalW + wNew) + max(maxH, hNew) + openBias;\n\n        bool doOpen = false;\n        if(bestC==-1) doOpen = true;\n        else if(openObj < bestObj) doOpen = true;\n\n        if(doOpen){\n            cols.push_back({wNew,hNew,i});\n            totalW += wNew;\n            maxH = max(maxH, hNew);\n            ops.push_back({i,hr,'L',-1});\n        }else{\n            auto [ww,hh] = dims(w,h,i,bestR);\n            cols[bestC].H += hh;\n            maxH = max(maxH, cols[bestC].H);\n            int b = (bestC==0 ? -1 : cols[bestC-1].headerIdx);\n            ops.push_back({i,bestR,'U',b});\n        }\n    }\n\n    Plan pl;\n    pl.ops = std::move(ops);\n    pl.predW = totalW;\n    pl.predH = maxH;\n    pl.predScore = totalW + maxH;\n    pl.tag = string(\"online_cols_bias=\") + to_string(openBias) + (headerMode==0 ? \"_wide\" : \"_narrow\");\n    return pl;\n}\n\nstatic uint64_t hash_plan_ops(const vector<Op>& ops){\n    // lightweight hash to drop exact duplicates\n    uint64_t x = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v){\n        x ^= v;\n        x *= 1099511628211ULL;\n    };\n    for(const auto& op: ops){\n        mix((uint64_t)op.p);\n        mix((uint64_t)op.r);\n        mix((uint64_t)op.d);\n        mix((uint64_t)(op.b + 2)); // shift\n    }\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    cin >> N >> T >> sigma;\n    vector<long long> w(N), h(N);\n    for(int i=0;i<N;i++) cin >> w[i] >> h[i];\n\n    mt19937_64 rng(123456789ULL);\n\n    vector<Plan> plans;\n\n    // Baselines\n    plans.push_back(make_single_row(w,h,0));\n    plans.push_back(make_single_row(w,h,1));\n    plans.push_back(make_single_col(w,h,0));\n    plans.push_back(make_single_col(w,h,1));\n\n    // Shelf row variants (contiguous), based on area scale\n    long double area = 0;\n    for(int i=0;i<N;i++) area += (long double)w[i] * (long double)h[i];\n    long long base = (long long) llround(sqrt((long double)max((long double)1.0, area)));\n    vector<long long> factors = {6,8,10,12,14,17,20,24,30,40};\n    for(long long f : factors){\n        long long M = max(1LL, base * f / 10);\n        plans.push_back(make_shelf_rows_width_limit(w,h,M));\n    }\n\n    // Prefix-columns brute force for m<=12\n    int Mmax = min(N, 12);\n    for(int m=2;m<=Mmax;m++){\n        Plan pl = make_prefix_columns_bruteforce(w,h,m);\n        if(pl.predScore < (1LL<<61)) plans.push_back(std::move(pl));\n    }\n\n    // Online columns with several biases (wide/narrow)\n    long long scale = max(10000LL, sigma * 5);\n    vector<long long> biases = {-4*scale, -2*scale, -scale, 0, scale, 2*scale, 4*scale};\n    for(long long b : biases){\n        plans.push_back(make_online_columns(w,h,b,0,nullptr));\n        plans.push_back(make_online_columns(w,h,b,1,nullptr));\n    }\n\n    // Additional randomized online plans to increase diversity\n    for(int it=0; it<800; it++){\n        long long b = (long long)((int64_t)(rng()% (uint64_t)(8*scale+1)) - (int64_t)(4*scale));\n        int headerMode = (rng()&1ULL) ? 0 : 1;\n        plans.push_back(make_online_columns(w,h,b,headerMode,&rng));\n    }\n\n    // Sort by predicted score and drop duplicates\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b){\n        if(a.predScore != b.predScore) return a.predScore < b.predScore;\n        return a.tag < b.tag;\n    });\n\n    vector<Plan> uniq;\n    uniq.reserve(plans.size());\n    unordered_set<uint64_t> seen;\n    seen.reserve(plans.size()*2);\n\n    for(auto &pl : plans){\n        if((int)pl.ops.size() != N) continue;\n        uint64_t hv = hash_plan_ops(pl.ops);\n        if(seen.insert(hv).second){\n            uniq.push_back(std::move(pl));\n            if((int)uniq.size() >= 500) break; // enough diversity\n        }\n    }\n\n    // Interactive loop: output T plans (best first; then cycle through remaining/random-like ones)\n    for(int t=0;t<T;t++){\n        const Plan* pl;\n        if(t < (int)uniq.size()) pl = &uniq[t];\n        else pl = &uniq[t % (int)uniq.size()];\n\n        cout << pl->ops.size() << '\\n';\n        for(const auto& op : pl->ops){\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        long long Wp, Hp;\n        if(!(cin >> Wp >> Hp)) break; // safety for non-interactive runs\n        // We do not adapt online in this simple solver.\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 1000;\nstatic const uint8_t INF8 = 255;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Bits {\n    static constexpr int W = (MAXN + 63) / 64;\n    array<uint64_t, W> a{};\n    void reset() { a.fill(0); }\n    void set(int i) { a[i >> 6] |= 1ULL << (i & 63); }\n    bool any() const { for (auto x : a) if (x) return true; return false; }\n};\n\nstatic inline int popcount_and(const Bits &x, const Bits &y) {\n    int s = 0;\n    for (int i = 0; i < Bits::W; i++) s += __builtin_popcountll(x.a[i] & y.a[i]);\n    return s;\n}\nstatic inline void andnot_inplace(Bits &x, const Bits &mask) {\n    for (int i = 0; i < Bits::W; i++) x.a[i] &= ~mask.a[i];\n}\nstatic inline double u01(uint64_t r) {\n    return (r >> 11) * (1.0 / 9007199254740992.0);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    vector<bitset<MAXN>> adjbs(N);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        adjbs[u].set(v);\n        adjbs[v].set(u);\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Precompute distances up to H (truncated BFS)\n    vector<vector<uint8_t>> dist(N, vector<uint8_t>(N, INF8));\n    {\n        deque<int> q;\n        vector<int> dd(N);\n        for (int s = 0; s < N; s++) {\n            fill(dd.begin(), dd.end(), -1);\n            dd[s] = 0;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                int dv = dd[v];\n                if (dv > H) continue;\n                dist[s][v] = (uint8_t)dv;\n                if (dv == H) continue;\n                for (int to : adj[v]) if (dd[to] == -1) {\n                    dd[to] = dv + 1;\n                    q.push_back(to);\n                }\n            }\n        }\n    }\n\n    vector<Bits> coverMask(N);\n    vector<vector<int>> coverList(N);\n    for (int s = 0; s < N; s++) {\n        coverMask[s].reset();\n        coverList[s].reserve(N);\n        for (int v = 0; v < N; v++) if (dist[s][v] != INF8) {\n            coverMask[s].set(v);\n            coverList[s].push_back(v);\n        }\n    }\n\n    // Root selection: greedy set cover + prune + shift + prune\n    vector<int> roots;\n    {\n        Bits uncovered;\n        uncovered.reset();\n        for (int v = 0; v < N; v++) uncovered.set(v);\n\n        while (uncovered.any()) {\n            int best = -1, bestGain = -1, bestA = 1e9;\n            for (int c = 0; c < N; c++) {\n                int gain = popcount_and(coverMask[c], uncovered);\n                if (gain > bestGain || (gain == bestGain && A[c] < bestA)) {\n                    bestGain = gain;\n                    bestA = A[c];\n                    best = c;\n                }\n            }\n            roots.push_back(best);\n            andnot_inplace(uncovered, coverMask[best]);\n        }\n\n        vector<int> coverCnt(N, 0);\n        int zeroCnt = N;\n        auto add_root = [&](int r) {\n            for (int v : coverList[r]) {\n                if (coverCnt[v] == 0) zeroCnt--;\n                coverCnt[v]++;\n            }\n        };\n        auto remove_root = [&](int r) {\n            for (int v : coverList[r]) {\n                coverCnt[v]--;\n                if (coverCnt[v] == 0) zeroCnt++;\n            }\n        };\n        for (int r : roots) add_root(r);\n\n        auto prune_once = [&]() -> bool {\n            bool changed = false;\n            sort(roots.begin(), roots.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] > A[j];\n                return i < j;\n            });\n            for (int i = 0; i < (int)roots.size(); ) {\n                int r = roots[i];\n                bool ok = true;\n                for (int v : coverList[r]) if (coverCnt[v] == 1) { ok = false; break; }\n                if (ok) {\n                    remove_root(r);\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                } else i++;\n            }\n            return changed;\n        };\n        while (prune_once()) {}\n\n        vector<char> isRoot(N, 0);\n        for (int r : roots) isRoot[r] = 1;\n\n        for (int idx = 0; idx < (int)roots.size(); idx++) {\n            int r = roots[idx];\n            vector<int> cand;\n            cand.reserve(30);\n            for (int v = 0; v < N; v++) if (dist[r][v] != INF8 && dist[r][v] <= 2) cand.push_back(v);\n            sort(cand.begin(), cand.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] < A[j];\n                return i < j;\n            });\n            int trials = min<int>(40, cand.size());\n            for (int t = 0; t < trials; t++) {\n                int c = cand[t];\n                if (c == r) break;\n                if (isRoot[c]) continue;\n                remove_root(r);\n                add_root(c);\n                if (zeroCnt == 0) {\n                    isRoot[r] = 0;\n                    isRoot[c] = 1;\n                    roots[idx] = c;\n                    r = c;\n                } else {\n                    remove_root(c);\n                    add_root(r);\n                }\n            }\n        }\n        while (prune_once()) {}\n    }\n\n    // Initial forest: multi-source BFS, tie-break by lower A parent\n    vector<int> parent(N, -2);\n    vector<int> depth(N, (int)1e9);\n    {\n        deque<int> q;\n        for (int r : roots) {\n            parent[r] = -1;\n            depth[r] = 0;\n            q.push_back(r);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (depth[v] == H) continue;\n            for (int to : adj[v]) {\n                int nd = depth[v] + 1;\n                if (nd < depth[to]) {\n                    depth[to] = nd;\n                    parent[to] = v;\n                    q.push_back(to);\n                } else if (nd == depth[to] && parent[to] != -1 && A[v] < A[parent[to]]) {\n                    parent[to] = v;\n                }\n            }\n        }\n        for (int v = 0; v < N; v++) if (parent[v] == -2) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n    }\n\n    // State structures\n    vector<vector<int>> children(N);\n    vector<int> childPos(N, -1);\n\n    vector<int> leaves;\n    vector<int> leafPos(N, -1);\n    vector<char> inLeaves(N, 0);\n\n    vector<int> rootsCur;\n    vector<int> rootPos(N, -1);\n    vector<char> inRoot(N, 0);\n\n    vector<int> subSumA(N, 0), subHeight(N, 0), subSize(N, 1);\n\n    vector<int> buf1, buf2;\n\n    auto build_children = [&](){\n        for (int i = 0; i < N; i++) {\n            children[i].clear();\n            childPos[i] = -1;\n        }\n        for (int v = 0; v < N; v++) if (parent[v] != -1) {\n            int p = parent[v];\n            childPos[v] = (int)children[p].size();\n            children[p].push_back(v);\n        }\n    };\n    auto remove_child = [&](int p, int v){\n        int idx = childPos[v];\n        int last = children[p].back();\n        children[p][idx] = last;\n        childPos[last] = idx;\n        children[p].pop_back();\n        childPos[v] = -1;\n    };\n    auto add_child = [&](int p, int v){\n        childPos[v] = (int)children[p].size();\n        children[p].push_back(v);\n    };\n\n    auto rebuild_roots_leaves = [&](){\n        rootsCur.clear();\n        leaves.clear();\n        fill(inRoot.begin(), inRoot.end(), 0);\n        fill(inLeaves.begin(), inLeaves.end(), 0);\n        fill(rootPos.begin(), rootPos.end(), -1);\n        fill(leafPos.begin(), leafPos.end(), -1);\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                inRoot[v] = 1;\n                rootPos[v] = (int)rootsCur.size();\n                rootsCur.push_back(v);\n            }\n        }\n        for (int v = 0; v < N; v++) {\n            if (children[v].empty()) {\n                inLeaves[v] = 1;\n                leafPos[v] = (int)leaves.size();\n                leaves.push_back(v);\n            }\n        }\n    };\n\n    auto make_root = [&](int v){\n        if (inRoot[v]) return;\n        inRoot[v] = 1;\n        rootPos[v] = (int)rootsCur.size();\n        rootsCur.push_back(v);\n    };\n    auto unmake_root = [&](int v){\n        if (!inRoot[v]) return;\n        int idx = rootPos[v];\n        int last = rootsCur.back();\n        rootsCur[idx] = last;\n        rootPos[last] = idx;\n        rootsCur.pop_back();\n        inRoot[v] = 0;\n        rootPos[v] = -1;\n    };\n\n    auto make_leaf = [&](int v){\n        if (inLeaves[v]) return;\n        inLeaves[v] = 1;\n        leafPos[v] = (int)leaves.size();\n        leaves.push_back(v);\n    };\n    auto unmake_leaf = [&](int v){\n        if (!inLeaves[v]) return;\n        int idx = leafPos[v];\n        int last = leaves.back();\n        leaves[idx] = last;\n        leafPos[last] = idx;\n        leaves.pop_back();\n        inLeaves[v] = 0;\n        leafPos[v] = -1;\n    };\n    auto refresh_leaf = [&](int v){\n        if (children[v].empty()) make_leaf(v);\n        else unmake_leaf(v);\n    };\n\n    auto is_ancestor = [&](int anc, int node) -> bool {\n        int cur = node;\n        for (int step = 0; step <= H + 5 && cur != -1; step++) {\n            if (cur == anc) return true;\n            cur = parent[cur];\n        }\n        return false;\n    };\n\n    auto recalc_node = [&](int v){\n        int sum = A[v];\n        int h = 0;\n        int sz = 1;\n        for (int ch : children[v]) {\n            sum += subSumA[ch];\n            sz += subSize[ch];\n            h = max(h, subHeight[ch] + 1);\n        }\n        subSumA[v] = sum;\n        subHeight[v] = h;\n        subSize[v] = sz;\n    };\n    auto recalc_up = [&](int v){\n        while (v != -1) {\n            int oldS = subSumA[v], oldH = subHeight[v], oldZ = subSize[v];\n            recalc_node(v);\n            if (subSumA[v] == oldS && subHeight[v] == oldH && subSize[v] == oldZ) break;\n            v = parent[v];\n        }\n    };\n    auto init_sub_aggregates = [&](){\n        for (int v = 0; v < N; v++) {\n            subSumA[v] = A[v];\n            subHeight[v] = 0;\n            subSize[v] = 1;\n        }\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; v++) layers[min(depth[v], H)].push_back(v);\n        for (int d = H; d >= 0; d--) {\n            for (int v : layers[d]) {\n                int p = parent[v];\n                if (p != -1) {\n                    subSumA[p] += subSumA[v];\n                    subSize[p] += subSize[v];\n                    subHeight[p] = max(subHeight[p], subHeight[v] + 1);\n                }\n            }\n        }\n    };\n\n    auto collect_subtree = [&](int v, vector<int>& nodes) {\n        nodes.clear();\n        vector<int> st;\n        st.push_back(v);\n        while (!st.empty()) {\n            int x = st.back(); st.pop_back();\n            nodes.push_back(x);\n            for (int ch : children[x]) st.push_back(ch);\n        }\n    };\n\n    auto rebuild_from_parent = [&](const vector<int>& par) -> long long {\n        parent = par;\n        build_children();\n\n        // recompute depth from roots\n        fill(depth.begin(), depth.end(), -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (parent[v] == -1) {\n            depth[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int ch : children[v]) {\n                depth[ch] = depth[v] + 1;\n                q.push_back(ch);\n            }\n        }\n        // safety (shouldn't happen)\n        for (int v = 0; v < N; v++) if (depth[v] == -1) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n\n        rebuild_roots_leaves();\n        init_sub_aggregates();\n\n        long long score = 0;\n        for (int v = 0; v < N; v++) score += 1LL * depth[v] * A[v];\n        return score;\n    };\n\n    build_children();\n    rebuild_roots_leaves();\n    init_sub_aggregates();\n\n    long long curScore = 0;\n    for (int v = 0; v < N; v++) curScore += 1LL * depth[v] * A[v];\n    long long bestScore = curScore;\n    vector<int> bestParent = parent;\n\n    auto potential = [&](int v) -> long long {\n        int slack = H - (depth[v] + subHeight[v]);\n        if (slack <= 0) return 0;\n        return 1LL * slack * subSumA[v];\n    };\n    auto selWeight = [&](int v) -> long long {\n        long long p = potential(v);\n        // cost-aware: prefer improvements per subtree size\n        return (p * 1024LL) / (subSize[v] + 32);\n    };\n\n    auto pick_best_among = [&](const vector<int>& pool, int k) -> int {\n        if (pool.empty()) return -1;\n        int best = pool[rng() % pool.size()];\n        long long bestW = selWeight(best);\n        for (int i = 1; i < k; i++) {\n            int v = pool[rng() % pool.size()];\n            long long w = selWeight(v);\n            if (w > bestW) { bestW = w; best = v; }\n        }\n        return best;\n    };\n\n    auto apply_reattach = [&](int v, int u, int delta) {\n        long long deltaScore = 1LL * delta * subSumA[v];\n\n        int oldp = parent[v];\n        if (oldp == -1) unmake_root(v);\n        if (oldp != -1) {\n            remove_child(oldp, v);\n            refresh_leaf(oldp);\n        }\n\n        parent[v] = u;\n        add_child(u, v);\n        refresh_leaf(u);\n\n        if (delta != 0) {\n            collect_subtree(v, buf1);\n            for (int x : buf1) depth[x] += delta;\n        }\n\n        curScore += deltaScore;\n\n        if (oldp != -1) recalc_up(oldp);\n        recalc_up(u);\n    };\n\n    auto try_reattach_SA = [&](int v, int u, double T) -> bool {\n        if (u == v) return false;\n        if (!adjbs[v].test(u)) return false;\n        if (is_ancestor(v, u)) return false;\n\n        int newDepthV = depth[u] + 1;\n        if (newDepthV > H) return false;\n        if (newDepthV + subHeight[v] > H) return false;\n\n        int delta = newDepthV - depth[v];\n        long long deltaScore = 1LL * delta * subSumA[v];\n        if (deltaScore >= 0) {\n            apply_reattach(v, u, delta);\n            return true;\n        }\n\n        if (subSize[v] >= 450) return false;\n        if ((double)(-deltaScore) > 6.0 * T) return false;\n\n        double p = exp((double)deltaScore / T);\n        if (u01(rng()) < p) {\n            apply_reattach(v, u, delta);\n            return true;\n        }\n        return false;\n    };\n\n    auto best_deeper_neighbor = [&](int v) -> int {\n        int bestU = -1, bestD = -1;\n        int limit = H - 1 - subHeight[v];\n        for (int u : adj[v]) {\n            if (depth[u] > limit) continue;\n            int nd = depth[u] + 1;\n            if (nd <= depth[v]) continue;\n            if (is_ancestor(v, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    // Sideways move (delta=0): change parent while keeping same depth\n    auto try_sideways = [&](int v) -> bool {\n        if (parent[v] == -1) return false;\n        int dv = depth[v];\n        int bestU = -1;\n        int bestH = INT_MAX;\n        for (int u : adj[v]) {\n            if (u == parent[v]) continue;\n            if (depth[u] + 1 != dv) continue; // ensures delta=0\n            if (is_ancestor(v, u)) continue;\n            // prefer parent with smaller subtree height to help future shaving/merge flexibility\n            if (subHeight[u] < bestH) {\n                bestH = subHeight[u];\n                bestU = u;\n            }\n        }\n        if (bestU == -1) return false;\n        apply_reattach(v, bestU, 0);\n        return true;\n    };\n\n    auto eval_rotate = [&](int c) -> pair<bool,long long> {\n        int p = parent[c];\n        if (p == -1) return {false, 0};\n        int gp = parent[p];\n        if (gp != -1 && !adjbs[gp].test(c)) return {false, 0};\n\n        int maxAbsOther = depth[p];\n        for (int o : children[p]) if (o != c) {\n            maxAbsOther = max(maxAbsOther, depth[o] + subHeight[o]);\n        }\n        if (maxAbsOther > H - 1) return {false, 0};\n\n        long long gain = 1LL * subSumA[p] - 2LL * subSumA[c];\n        return {true, gain};\n    };\n\n    auto apply_rotate = [&](int c, long long gain) {\n        int p = parent[c];\n        int gp = parent[p];\n\n        collect_subtree(p, buf1);\n        collect_subtree(c, buf2);\n\n        remove_child(p, c);\n        refresh_leaf(p);\n\n        if (gp != -1) {\n            remove_child(gp, p);\n            refresh_leaf(gp);\n            parent[c] = gp;\n            add_child(gp, c);\n            refresh_leaf(gp);\n        } else {\n            parent[c] = -1;\n            make_root(c);\n            unmake_root(p);\n        }\n\n        parent[p] = c;\n        add_child(c, p);\n        refresh_leaf(c);\n\n        for (int x : buf1) depth[x] += 1;\n        for (int x : buf2) depth[x] -= 2;\n\n        curScore += gain;\n\n        recalc_up(p);\n        recalc_up(c);\n        if (gp != -1) recalc_up(gp);\n    };\n\n    auto try_rotate_SA = [&](int c, double T) -> bool {\n        auto [ok, gain] = eval_rotate(c);\n        if (!ok) return false;\n\n        if (gain >= 0) {\n            apply_rotate(c, gain);\n            return true;\n        }\n\n        int p = parent[c];\n        if (p != -1 && subSize[p] >= 600) return false;\n        if ((double)(-gain) > 6.0 * T) return false;\n\n        double pacc = exp((double)gain / T);\n        if (u01(rng()) < pacc) {\n            apply_rotate(c, gain);\n            return true;\n        }\n        return false;\n    };\n\n    auto best_external_neighbor_for_root = [&](int r) -> int {\n        int bestU = -1, bestD = -1;\n        int limit = H - 1 - subHeight[r];\n        for (int u : adj[r]) {\n            if (depth[u] > limit) continue;\n            if (is_ancestor(r, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    auto shave_once = [&](double T) -> bool {\n        if (rootsCur.empty()) return false;\n\n        int r = -1;\n        for (int t = 0; t < 10; t++) {\n            int cand = rootsCur[rng() % rootsCur.size()];\n            if (subHeight[cand] == H) { r = cand; break; }\n            if (r == -1) r = cand;\n        }\n        if (r == -1 || subHeight[r] < H) return false;\n\n        int cur = r;\n        for (int step = 0; step < H; step++) {\n            int nxt = -1;\n            int bestSum = INT_MAX;\n            for (int ch : children[cur]) {\n                if (subHeight[ch] + 1 == subHeight[cur]) {\n                    if (subSumA[ch] < bestSum) {\n                        bestSum = subSumA[ch];\n                        nxt = ch;\n                    }\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        int v = cur;\n\n        int bestU = -1;\n        int bestDepthU = INT_MAX;\n        for (int u : adj[v]) {\n            if (is_ancestor(v, u)) continue;\n            int newDepthV = depth[u] + 1;\n            if (newDepthV + subHeight[v] > H) continue;\n            if (newDepthV >= depth[v]) continue;\n            if (depth[u] < bestDepthU) {\n                bestDepthU = depth[u];\n                bestU = u;\n            }\n        }\n        if (bestU == -1) return false;\n        return try_reattach_SA(v, bestU, T);\n    };\n\n    // Warm-up greedy deepening\n    {\n        vector<int> allNodes(N);\n        iota(allNodes.begin(), allNodes.end(), 0);\n        sort(allNodes.begin(), allNodes.end(), [&](int i, int j){\n            long long wi = selWeight(i), wj = selWeight(j);\n            if (wi != wj) return wi > wj;\n            return A[i] > A[j];\n        });\n        int tries = min(N, 350);\n        for (int t = 0; t < tries; t++) {\n            int v = allNodes[t];\n            for (int rep = 0; rep < 2; rep++) {\n                int u = best_deeper_neighbor(v);\n                if (u == -1) break;\n                (void)try_reattach_SA(v, u, 1e-9);\n            }\n        }\n        if (curScore > bestScore) { bestScore = curScore; bestParent = parent; }\n    }\n\n    // SA with cyclic reheating and restart from best\n    Timer timer;\n    const double TL = 1.98;\n    const double cycles = 3.0;\n    const double cycleLen = TL / cycles;\n    const double T0 = 60000.0;\n    const double T1 = 60.0;\n\n    double nextReset = cycleLen;\n\n    vector<int> allNodes(N);\n    iota(allNodes.begin(), allNodes.end(), 0);\n\n    while (timer.elapsed_sec() < TL) {\n        double elapsed = timer.elapsed_sec();\n\n        if (elapsed >= nextReset) {\n            // restart from best at cycle boundary\n            curScore = rebuild_from_parent(bestParent);\n            nextReset += cycleLen;\n        }\n\n        double cycleStart = floor(elapsed / cycleLen) * cycleLen;\n        double frac = (elapsed - cycleStart) / cycleLen;\n        double T = T0 * pow(T1 / T0, frac);\n\n        int mode = (int)(rng() % 100);\n\n        if (mode < 36) {\n            int v = pick_best_among(leaves, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 56) {\n            int v = pick_best_among(allNodes, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 70) {\n            // sideways structural move (cheap)\n            int v = pick_best_among(allNodes, 8);\n            if (v == -1) continue;\n            (void)try_sideways(v);\n\n        } else if (mode < 84) {\n            // root merge tournament\n            if (rootsCur.size() <= 1) continue;\n            int bestR = -1, bestU = -1;\n            long long bestGain = -1;\n            for (int t = 0; t < 10; t++) {\n                int rrt = rootsCur[rng() % rootsCur.size()];\n                int u = best_external_neighbor_for_root(rrt);\n                if (u == -1) continue;\n                long long gain = 1LL * (depth[u] + 1) * subSumA[rrt];\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestR = rrt;\n                    bestU = u;\n                }\n            }\n            if (bestR != -1) (void)try_reattach_SA(bestR, bestU, T);\n\n        } else if (mode < 90) {\n            // random reattach (SA)\n            int v = (int)(rng() % N);\n            int u = adj[v][rng() % adj[v].size()];\n            (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 96) {\n            // rotation best-of-a-few\n            int bestC = -1;\n            long long bestG = LLONG_MIN;\n            for (int t = 0; t < 12; t++) {\n                int p = (int)(rng() % N);\n                if (children[p].empty()) continue;\n                int c = children[p][rng() % children[p].size()];\n                auto [ok, g] = eval_rotate(c);\n                if (!ok) continue;\n                if (g > bestG) { bestG = g; bestC = c; }\n            }\n            if (bestC != -1) (void)try_rotate_SA(bestC, T);\n\n        } else {\n            (void)shave_once(T);\n        }\n\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestParent = parent;\n        }\n    }\n\n    // Final safety repair on bestParent\n    auto repair = [&](vector<int>& par){\n        vector<int> state(N, 0);\n        for (int v = 0; v < N; v++) {\n            if (state[v]) continue;\n            int cur = v;\n            while (cur != -1 && state[cur] == 0) {\n                state[cur] = 1;\n                cur = par[cur];\n            }\n            if (cur != -1 && state[cur] == 1) par[v] = -1;\n            cur = v;\n            while (cur != -1 && state[cur] == 1) {\n                state[cur] = 2;\n                cur = par[cur];\n            }\n        }\n        for (int v = 0; v < N; v++) {\n            if (par[v] == -1) continue;\n            if (!adjbs[v].test(par[v])) par[v] = -1;\n        }\n\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) if (par[v] != -1) ch[par[v]].push_back(v);\n\n        vector<int> dep(N, -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (par[v] == -1) {\n            dep[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int to : ch[v]) {\n                dep[to] = dep[v] + 1;\n                q.push_back(to);\n            }\n        }\n        for (int v = 0; v < N; v++) if (dep[v] == -1) {\n            par[v] = -1;\n            dep[v] = 0;\n        }\n        for (int v = 0; v < N; v++) if (dep[v] > H) par[v] = -1;\n    };\n\n    repair(bestParent);\n\n    for (int i = 0; i < N; i++) {\n        cout << bestParent[i] << (i + 1 == N ? '\\n' : ' ');\n    }\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int G = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr int INF = 1e9;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto t = steady_clock::now() - st;\n    return duration<double>(t).count();\n}\n\nstatic inline int gid(int type, int idx) {\n    // type: 0=Ucol,1=Dcol,2=Lrow,3=Rrow\n    if (type == 0) return idx;\n    if (type == 1) return 20 + idx;\n    if (type == 2) return 40 + idx;\n    return 60 + idx;\n}\n\nstruct Oni {\n    int r, c;\n    array<char,4> valid{};\n    array<int,4> group{};\n    array<int,4> depth{};\n    vector<int> feas;\n    bool fixed = false;\n    int bestSingleDepth = 999;\n};\n\nstruct AssignState {\n    vector<int> dir;                      // per local id\n    array<array<uint8_t, MAXD+1>, G> cnt; // counts per depth\n    array<uint8_t, G> mx;                 // max depth per group\n    int cost = 0;                         // sum mx\n};\n\nstruct AssignResult {\n    array<int,G> mx{};\n    int sumDepth = 0;\n    vector<int> dirGlobal; // size M if requested\n};\n\nstruct LineSel { bool isRow; int idx; };\n\nstruct Cand {\n    uint64_t remMask;\n    int clearMoves;\n    vector<LineSel> seq;\n    int approxTotal;\n};\n\nstruct Plan {\n    vector<LineSel> seq;\n    int clearMoves = 0;\n    array<int,G> mx{};\n    int sumDepth = 0;\n    int totalMoves() const { return clearMoves + 2 * sumDepth; }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<string> C(n);\n    for (int i = 0; i < n; i++) cin >> C[i];\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937_64 rng(seed);\n    auto rint = [&](int lo, int hi) {\n        uniform_int_distribution<int> dist(lo, hi);\n        return dist(rng);\n    };\n    auto r01 = [&]() {\n        uniform_real_distribution<double> dist(0.0, 1.0);\n        return dist(rng);\n    };\n\n    double tStart = now_sec();\n    const double TL = 1.95;\n\n    // Fuku existence\n    array<int,N> rowHasFuku{}, colHasFuku{};\n    rowHasFuku.fill(0); colHasFuku.fill(0);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (C[i][j] == 'o') {\n        rowHasFuku[i] = 1;\n        colHasFuku[j] = 1;\n    }\n\n    // Limits from Fuku positions (restore-safe bounds)\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    left_limit.fill(N); right_limit.fill(N); up_limit.fill(N); down_limit.fill(N);\n\n    for (int i = 0; i < N; i++) {\n        int first = N, last = -1;\n        for (int j = 0; j < N; j++) if (C[i][j] == 'o') {\n            first = min(first, j);\n            last = max(last, j);\n        }\n        left_limit[i] = first;\n        right_limit[i] = (last == -1 ? N : (N-1-last));\n    }\n    for (int j = 0; j < N; j++) {\n        int first = N, last = -1;\n        for (int i = 0; i < N; i++) if (C[i][j] == 'o') {\n            first = min(first, i);\n            last = max(last, i);\n        }\n        up_limit[j] = first;\n        down_limit[j] = (last == -1 ? N : (N-1-last));\n    }\n\n    array<int,G> lim{};\n    for (int j = 0; j < N; j++) {\n        lim[gid(0,j)] = min(up_limit[j], MAXD);\n        lim[gid(1,j)] = min(down_limit[j], MAXD);\n    }\n    for (int i = 0; i < N; i++) {\n        lim[gid(2,i)] = min(left_limit[i], MAXD);\n        lim[gid(3,i)] = min(right_limit[i], MAXD);\n    }\n\n    // Collect Oni positions\n    vector<pair<int,int>> oniPos;\n    oniPos.reserve(40);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (C[i][j] == 'x') oniPos.push_back({i,j});\n    int M = (int)oniPos.size(); // 40\n    uint64_t FULL = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n\n    // Build Oni options\n    vector<Oni> onis;\n    onis.reserve(M);\n    for (auto [r,c] : oniPos) {\n        Oni o;\n        o.r = r; o.c = c;\n\n        { int K = r + 1; int g = gid(0, c);\n          if (K <= lim[g]) { o.valid[0]=1; o.group[0]=g; o.depth[0]=K; o.feas.push_back(0); } }\n        { int K = N - r; int g = gid(1, c);\n          if (K <= lim[g]) { o.valid[1]=1; o.group[1]=g; o.depth[1]=K; o.feas.push_back(1); } }\n        { int K = c + 1; int g = gid(2, r);\n          if (K <= lim[g]) { o.valid[2]=1; o.group[2]=g; o.depth[2]=K; o.feas.push_back(2); } }\n        { int K = N - c; int g = gid(3, r);\n          if (K <= lim[g]) { o.valid[3]=1; o.group[3]=g; o.depth[3]=K; o.feas.push_back(3); } }\n\n        if (o.feas.empty()) { // should not happen by guarantee\n            o.valid[0]=1; o.group[0]=gid(0,c); o.depth[0]=1; o.feas.push_back(0);\n        }\n        o.fixed = (o.feas.size() == 1);\n        int best = 999;\n        for (int d : o.feas) best = min(best, o.depth[d]);\n        o.bestSingleDepth = best;\n\n        onis.push_back(o);\n    }\n\n    // Precompute Oni sets per row/col (static positions)\n    array<uint64_t,N> rowMask{}, colMask{};\n    rowMask.fill(0); colMask.fill(0);\n    array<vector<int>,N> rowList, colList;\n    for (int i = 0; i < N; i++) { rowList[i].clear(); colList[i].clear(); }\n\n    for (int i = 0; i < M; i++) {\n        auto [r,c] = oniPos[i];\n        rowMask[r] |= (1ULL << i);\n        colMask[c] |= (1ULL << i);\n        rowList[r].push_back(i);\n        colList[c].push_back(i);\n    }\n\n    auto clear_cost_row = [&](int r, uint64_t alive)->pair<int,char> {\n        int mn = INF, mx = -1;\n        for (int id : rowList[r]) if (alive & (1ULL << id)) {\n            mn = min(mn, onis[id].c);\n            mx = max(mx, onis[id].c);\n        }\n        if (mx < 0) return {0, 'L'};\n        int kL = mx + 1;\n        int kR = N - mn;\n        if (kL <= kR) return {kL, 'L'};\n        return {kR, 'R'};\n    };\n    auto clear_cost_col = [&](int c, uint64_t alive)->pair<int,char> {\n        int mn = INF, mx = -1;\n        for (int id : colList[c]) if (alive & (1ULL << id)) {\n            mn = min(mn, onis[id].r);\n            mx = max(mx, onis[id].r);\n        }\n        if (mx < 0) return {0, 'U'};\n        int kU = mx + 1;\n        int kD = N - mn;\n        if (kU <= kD) return {kU, 'U'};\n        return {kD, 'D'};\n    };\n\n    // minReq[g][i] = required depth in group g to cover oni i, INF if impossible\n    vector<array<int,64>> minReq(G);\n    for (int g = 0; g < G; g++) for (int i = 0; i < 64; i++) minReq[g][i] = INF;\n    for (int i = 0; i < M; i++) {\n        auto [r,c] = oniPos[i];\n        // U\n        { int g = gid(0,c); int need = r+1; if (need <= lim[g]) minReq[g][i] = need; }\n        // D\n        { int g = gid(1,c); int need = N-r; if (need <= lim[g]) minReq[g][i] = need; }\n        // L\n        { int g = gid(2,r); int need = c+1; if (need <= lim[g]) minReq[g][i] = need; }\n        // R\n        { int g = gid(3,r); int need = N-c; if (need <= lim[g]) minReq[g][i] = need; }\n    }\n\n    // Cover-based critical prune for remaining set (guaranteed non-increasing sumDepth)\n    auto critical_prune = [&](array<int,G>& depth, const vector<int>& remIds) {\n        if (remIds.empty()) return;\n        // iterate until stable\n        for (int iter = 0; iter < 60; iter++) {\n            // compute cover counts\n            array<int,64> coverCnt{};\n            coverCnt.fill(0);\n            for (int g = 0; g < G; g++) if (depth[g] > 0) {\n                int d = depth[g];\n                for (int id : remIds) {\n                    if (minReq[g][id] <= d) coverCnt[id]++;\n                }\n            }\n            bool changed = false;\n            // try reduce each group\n            for (int g = 0; g < G; g++) {\n                int d = depth[g];\n                if (d == 0) continue;\n                int need = 0;\n                for (int id : remIds) {\n                    if (minReq[g][id] <= d && coverCnt[id] == 1) {\n                        need = max(need, minReq[g][id]);\n                    }\n                }\n                if (need < d) {\n                    depth[g] = need;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    };\n\n    // Assignment-SA on a subset\n    auto solve_assignment = [&](const vector<int>& ids,\n                               const vector<int>* initDirGlobal,\n                               double timeBudgetSec,\n                               bool wantDirGlobal)->AssignResult {\n        AssignResult res;\n        res.mx.fill(0);\n        res.sumDepth = 0;\n        if (wantDirGlobal) res.dirGlobal.assign(M, 0);\n        int m = (int)ids.size();\n        if (m == 0) return res;\n\n        auto build_greedy_min_local = [&]() {\n            vector<int> dir(m, 0);\n            for (int i = 0; i < m; i++) {\n                int oid = ids[i];\n                int bestDep = INF;\n                vector<int> ties;\n                for (int d : onis[oid].feas) {\n                    int dep = onis[oid].depth[d];\n                    if (dep < bestDep) { bestDep = dep; ties = {d}; }\n                    else if (dep == bestDep) ties.push_back(d);\n                }\n                dir[i] = ties[rint(0, (int)ties.size()-1)];\n            }\n            return dir;\n        };\n        auto build_from_init_global = [&]() {\n            vector<int> dir(m, 0);\n            for (int i = 0; i < m; i++) {\n                int oid = ids[i];\n                dir[i] = (*initDirGlobal)[oid];\n            }\n            return dir;\n        };\n        auto build_random_local = [&]() {\n            vector<int> dir(m, 0);\n            for (int i = 0; i < m; i++) {\n                int oid = ids[i];\n                const auto& f = onis[oid].feas;\n                dir[i] = f[rint(0, (int)f.size()-1)];\n            }\n            return dir;\n        };\n\n        auto build_state = [&](const vector<int>& dirLocal) {\n            AssignState st;\n            st.dir = dirLocal;\n            for (int g = 0; g < G; g++) {\n                st.mx[g] = 0;\n                for (int d = 0; d <= MAXD; d++) st.cnt[g][d] = 0;\n            }\n            st.cost = 0;\n            auto add = [&](int g, int d) {\n                st.cnt[g][d]++;\n                if (d > st.mx[g]) {\n                    st.cost += (d - st.mx[g]);\n                    st.mx[g] = (uint8_t)d;\n                }\n            };\n            for (int i = 0; i < m; i++) {\n                int oid = ids[i];\n                int d = st.dir[i];\n                add(onis[oid].group[d], onis[oid].depth[d]);\n            }\n            return st;\n        };\n\n        auto remove_from = [&](AssignState& st, int g, int d) {\n            st.cnt[g][d]--;\n            if (d == st.mx[g] && st.cnt[g][d] == 0) {\n                int old = st.mx[g];\n                int nd = 0;\n                for (int x = old - 1; x >= 1; x--) if (st.cnt[g][x] > 0) { nd = x; break; }\n                st.mx[g] = (uint8_t)nd;\n                st.cost += (nd - old);\n            }\n        };\n        auto add_to = [&](AssignState& st, int g, int d) {\n            st.cnt[g][d]++;\n            if (d > st.mx[g]) {\n                st.cost += (d - st.mx[g]);\n                st.mx[g] = (uint8_t)d;\n            }\n        };\n        auto apply_change = [&](AssignState& st, int i, int nd) {\n            int od = st.dir[i];\n            if (od == nd) return 0;\n            int oid = ids[i];\n            int og = onis[oid].group[od], odp = onis[oid].depth[od];\n            int ng = onis[oid].group[nd], ndp = onis[oid].depth[nd];\n            int before = st.cost;\n            remove_from(st, og, odp);\n            add_to(st, ng, ndp);\n            st.dir[i] = nd;\n            return st.cost - before;\n        };\n\n        auto greedy_improve_one = [&](AssignState& st, int i)->bool {\n            int oid = ids[i];\n            if (onis[oid].fixed) return false;\n            int od = st.dir[i];\n            int bestd = od;\n            int bestCost = st.cost;\n            for (int nd : onis[oid].feas) {\n                if (nd == od) continue;\n                apply_change(st, i, nd);\n                int c = st.cost;\n                apply_change(st, i, od);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestd = nd;\n                }\n            }\n            if (bestd != od) {\n                apply_change(st, i, bestd);\n                return true;\n            }\n            return false;\n        };\n\n        double stt = now_sec();\n        double deadline = stt + timeBudgetSec;\n\n        // Choose best initial among (initDirGlobal) and greedy-min\n        vector<int> init1 = build_greedy_min_local();\n        AssignState bestSt = build_state(init1);\n\n        if (initDirGlobal) {\n            vector<int> init2 = build_from_init_global();\n            AssignState st2 = build_state(init2);\n            if (st2.cost < bestSt.cost) bestSt = st2;\n        }\n\n        AssignState curSt = bestSt;\n\n        int restarts = (timeBudgetSec >= 0.18 ? 3 : 1);\n        for (int rs = 0; rs < restarts; rs++) {\n            if (now_sec() >= deadline) break;\n\n            vector<int> init;\n            if (rs == 0) {\n                init = bestSt.dir;\n            } else {\n                init = build_random_local();\n            }\n            curSt = build_state(init);\n\n            double segStart = now_sec();\n            double segEnd = stt + timeBudgetSec * (rs + 1) / restarts;\n\n            const double T0 = 25.0, T1 = 0.7;\n            long long iter = 0;\n\n            while (true) {\n                double tnow = now_sec();\n                if (tnow >= segEnd || tnow >= deadline) break;\n                double p = (tnow - segStart) / max(1e-9, segEnd - segStart);\n                p = min(1.0, max(0.0, p));\n                double temp = T0 * (1.0 - p) + T1 * p;\n\n                int i = rint(0, m-1);\n                int oid = ids[i];\n                if (onis[oid].fixed) continue;\n                const auto& f = onis[oid].feas;\n                if ((int)f.size() <= 1) continue;\n\n                int od = curSt.dir[i];\n                int nd = od;\n                for (int tries = 0; tries < 8; tries++) {\n                    nd = f[rint(0, (int)f.size()-1)];\n                    if (nd != od) break;\n                }\n                if (nd == od) continue;\n\n                int delta = apply_change(curSt, i, nd);\n                bool accept = false;\n                if (delta <= 0) accept = true;\n                else if (r01() < exp(-(double)delta / temp)) accept = true;\n\n                if (!accept) {\n                    apply_change(curSt, i, od);\n                } else {\n                    if (curSt.cost < bestSt.cost) bestSt = curSt;\n                }\n\n                if ((++iter & 4095) == 0) {\n                    int j = rint(0, m-1);\n                    greedy_improve_one(curSt, j);\n                    if (curSt.cost < bestSt.cost) bestSt = curSt;\n                }\n            }\n\n            for (int pass = 0; pass < 8; pass++) {\n                bool imp = false;\n                for (int i = 0; i < m; i++) imp |= greedy_improve_one(curSt, i);\n                if (!imp) break;\n                if (curSt.cost < bestSt.cost) bestSt = curSt;\n            }\n        }\n\n        res.sumDepth = bestSt.cost;\n        for (int g = 0; g < G; g++) res.mx[g] = bestSt.mx[g];\n\n        if (wantDirGlobal) {\n            for (int i = 0; i < m; i++) {\n                int oid = ids[i];\n                res.dirGlobal[oid] = bestSt.dir[i];\n            }\n        }\n        return res;\n    };\n\n    // Baseline SA on all Oni to obtain baseDir and baseline mx\n    vector<int> allIds(M);\n    iota(allIds.begin(), allIds.end(), 0);\n\n    double baselineBudget = 0.62;\n    if (now_sec() - tStart > 0.05) baselineBudget = max(0.30, 0.62 - (now_sec() - tStart));\n    AssignResult base = solve_assignment(allIds, nullptr, baselineBudget, true);\n    vector<int> baseDir = base.dirGlobal;\n\n    // For fast approximate restore cost: use baseDir fixed assignment\n    vector<int> baseGroup(M), baseDep(M);\n    for (int i = 0; i < M; i++) {\n        int d = baseDir[i];\n        baseGroup[i] = onis[i].group[d];\n        baseDep[i] = onis[i].depth[d];\n    }\n\n    unordered_map<uint64_t, int> approxCache;\n    approxCache.reserve(4096);\n    auto approx_restore_cost = [&](uint64_t aliveMask)->int {\n        auto it = approxCache.find(aliveMask);\n        if (it != approxCache.end()) return it->second;\n        array<int,G> mx{};\n        mx.fill(0);\n        for (int i = 0; i < M; i++) if (aliveMask & (1ULL << i)) {\n            int g = baseGroup[i];\n            mx[g] = max(mx[g], baseDep[i]);\n        }\n        int sum = 0;\n        for (int g = 0; g < G; g++) sum += mx[g];\n        approxCache.emplace(aliveMask, sum);\n        return sum;\n    };\n\n    // Eligible Fuku-free lines\n    vector<LineSel> eligible;\n    eligible.reserve(40);\n    for (int r = 0; r < N; r++) if (!rowHasFuku[r] && rowMask[r]) eligible.push_back({true, r});\n    for (int c = 0; c < N; c++) if (!colHasFuku[c] && colMask[c]) eligible.push_back({false, c});\n\n    // Generate many randomized greedy sequences; allow occasional negative steps\n    vector<Cand> cands;\n    cands.reserve(1024);\n    unordered_map<uint64_t,int> bestIdx; // remMask -> index in cands\n    bestIdx.reserve(2048);\n\n    auto gen_one_sequence = [&]() -> Cand {\n        uint64_t alive = FULL;\n        int clearMoves = 0;\n        vector<LineSel> seq;\n        seq.reserve(24);\n        array<char,N> usedRow{}, usedCol{};\n        usedRow.fill(0); usedCol.fill(0);\n\n        int steps = 0;\n        while (alive && steps < 24) {\n            int baseCost = approx_restore_cost(alive);\n\n            struct Opt { int gain; LineSel ls; uint64_t na; int k; };\n            vector<Opt> opts;\n            opts.reserve(64);\n\n            for (auto ls : eligible) {\n                if (ls.isRow) {\n                    int r = ls.idx;\n                    if (usedRow[r]) continue;\n                    uint64_t onLine = alive & rowMask[r];\n                    if (!onLine) continue;\n                    auto [k, dir] = clear_cost_row(r, alive);\n                    uint64_t na = alive & ~rowMask[r];\n                    int newCost = approx_restore_cost(na);\n                    int gain = 2 * (baseCost - newCost) - k;\n                    opts.push_back({gain, ls, na, k});\n                } else {\n                    int c = ls.idx;\n                    if (usedCol[c]) continue;\n                    uint64_t onLine = alive & colMask[c];\n                    if (!onLine) continue;\n                    auto [k, dir] = clear_cost_col(c, alive);\n                    uint64_t na = alive & ~colMask[c];\n                    int newCost = approx_restore_cost(na);\n                    int gain = 2 * (baseCost - newCost) - k;\n                    opts.push_back({gain, ls, na, k});\n                }\n            }\n\n            if (opts.empty()) break;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b){ return a.gain > b.gain; });\n\n            int bestGain = opts[0].gain;\n            // stop normally if no positive gain, but sometimes continue to enable combos\n            if (bestGain <= 0) {\n                double contProb = 0.18; // exploration probability\n                if (r01() > contProb) break;\n            }\n\n            int K = min<int>(8, opts.size());\n            // softmax-like choice among top-K\n            double tau = 6.0;\n            double sumw = 0.0;\n            array<double,8> w{};\n            for (int i = 0; i < K; i++) {\n                // clamp to avoid huge exp\n                double x = max(-50.0, min(50.0, (double)opts[i].gain / tau));\n                w[i] = exp(x);\n                sumw += w[i];\n            }\n            double pick = r01() * sumw;\n            int choose = 0;\n            for (int i = 0; i < K; i++) {\n                pick -= w[i];\n                if (pick <= 0) { choose = i; break; }\n            }\n\n            auto sel = opts[choose];\n            seq.push_back(sel.ls);\n            clearMoves += sel.k;\n            alive = sel.na;\n            if (sel.ls.isRow) usedRow[sel.ls.idx] = 1;\n            else usedCol[sel.ls.idx] = 1;\n            steps++;\n\n            if (clearMoves > 4*N*N) break;\n        }\n\n        Cand cd;\n        cd.remMask = alive;\n        cd.clearMoves = clearMoves;\n        cd.seq = std::move(seq);\n        cd.approxTotal = clearMoves + 2 * approx_restore_cost(alive);\n        return cd;\n    };\n\n    double genEnd = tStart + 1.30;\n    if (!eligible.empty()) {\n        while (now_sec() < genEnd) {\n            Cand cd = gen_one_sequence();\n            if (cd.clearMoves > 4*N*N) continue;\n            auto it = bestIdx.find(cd.remMask);\n            if (it == bestIdx.end()) {\n                int idx = (int)cands.size();\n                bestIdx.emplace(cd.remMask, idx);\n                cands.push_back(std::move(cd));\n            } else {\n                Cand &cur = cands[it->second];\n                if (cd.clearMoves < cur.clearMoves) cur = std::move(cd);\n            }\n        }\n    }\n\n    // Always include baseline (no clears)\n    {\n        Cand cd;\n        cd.remMask = FULL;\n        cd.clearMoves = 0;\n        cd.seq.clear();\n        cd.approxTotal = 2 * approx_restore_cost(FULL);\n        cands.push_back(std::move(cd));\n    }\n\n    sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b){\n        return a.approxTotal < b.approxTotal;\n    });\n\n    int shortlist = min<int>(16, cands.size());\n\n    // Baseline plan as initial best\n    Plan bestPlan;\n    bestPlan.seq.clear();\n    bestPlan.clearMoves = 0;\n    bestPlan.mx = base.mx;\n    bestPlan.sumDepth = base.sumDepth;\n\n    // Exact evaluation on shortlist\n    for (int s = 0; s < shortlist; s++) {\n        double now = now_sec();\n        double remain = TL - (now - tStart);\n        if (remain <= 0.02) break;\n\n        const Cand &cd = cands[s];\n        vector<int> remIds;\n        remIds.reserve(M);\n        for (int i = 0; i < M; i++) if (cd.remMask & (1ULL << i)) remIds.push_back(i);\n\n        // time slice (a bit larger for early candidates)\n        double slice = min(0.22, max(0.04, remain / (shortlist - s) * 1.05));\n\n        AssignResult ar = solve_assignment(remIds, &baseDir, slice, false);\n\n        // cover-based prune can only help\n        array<int,G> pruned = ar.mx;\n        critical_prune(pruned, remIds);\n        int prunedSum = 0;\n        for (int g = 0; g < G; g++) prunedSum += pruned[g];\n\n        Plan pl;\n        pl.seq = cd.seq;\n        pl.clearMoves = cd.clearMoves;\n        pl.mx = pruned;\n        pl.sumDepth = prunedSum;\n\n        if (pl.totalMoves() <= 4*N*N && pl.totalMoves() < bestPlan.totalMoves()) {\n            bestPlan = pl;\n        }\n    }\n\n    // Build output\n    vector<pair<char,int>> out;\n    out.reserve(bestPlan.totalMoves());\n\n    uint64_t alive = FULL;\n    for (auto ls : bestPlan.seq) {\n        if (ls.isRow) {\n            int r = ls.idx;\n            uint64_t onLine = alive & rowMask[r];\n            if (!onLine) continue;\n            auto [k, dir] = clear_cost_row(r, alive);\n            for (int t = 0; t < k; t++) out.push_back({dir, r});\n            alive &= ~rowMask[r];\n        } else {\n            int c = ls.idx;\n            uint64_t onLine = alive & colMask[c];\n            if (!onLine) continue;\n            auto [k, dir] = clear_cost_col(c, alive);\n            for (int t = 0; t < k; t++) out.push_back({dir, c});\n            alive &= ~colMask[c];\n        }\n    }\n\n    auto add_repeat = [&](char ch, int idx, int k) {\n        for (int t = 0; t < k; t++) out.push_back({ch, idx});\n    };\n\n    // restore ops from bestPlan.mx\n    for (int j = 0; j < N; j++) {\n        int d = bestPlan.mx[gid(0,j)];\n        if (d) { add_repeat('U', j, d); add_repeat('D', j, d); }\n    }\n    for (int j = 0; j < N; j++) {\n        int d = bestPlan.mx[gid(1,j)];\n        if (d) { add_repeat('D', j, d); add_repeat('U', j, d); }\n    }\n    for (int i = 0; i < N; i++) {\n        int d = bestPlan.mx[gid(2,i)];\n        if (d) { add_repeat('L', i, d); add_repeat('R', i, d); }\n    }\n    for (int i = 0; i < N; i++) {\n        int d = bestPlan.mx[gid(3,i)];\n        if (d) { add_repeat('R', i, d); add_repeat('L', i, d); }\n    }\n\n    // Safety fallback\n    if ((int)out.size() > 4*N*N) {\n        out.clear();\n        // baseline restore only\n        auto add_repeat2 = [&](char ch, int idx, int k) {\n            for (int t = 0; t < k; t++) out.push_back({ch, idx});\n        };\n        for (int j = 0; j < N; j++) {\n            int d = base.mx[gid(0,j)];\n            if (d) { add_repeat2('U', j, d); add_repeat2('D', j, d); }\n        }\n        for (int j = 0; j < N; j++) {\n            int d = base.mx[gid(1,j)];\n            if (d) { add_repeat2('D', j, d); add_repeat2('U', j, d); }\n        }\n        for (int i = 0; i < N; i++) {\n            int d = base.mx[gid(2,i)];\n            if (d) { add_repeat2('L', i, d); add_repeat2('R', i, d); }\n        }\n        for (int i = 0; i < N; i++) {\n            int d = base.mx[gid(3,i)];\n            if (d) { add_repeat2('R', i, d); add_repeat2('L', i, d); }\n        }\n        if ((int)out.size() > 4*N*N) out.clear();\n    }\n\n    for (auto [d,p] : out) {\n        cout << d << \" \" << p << \"\\n\";\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 100;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int mod) { return (int)(nextU64() % (uint64_t)mod); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline int iabs_int(int x) { return x < 0 ? -x : x; }\nstatic inline long long iabs_ll(long long x) { return x < 0 ? -x : x; }\n\nstruct Plan {\n    array<int, N> a;\n    array<int, N> b;\n};\n\nint simulate_plan(const Plan& p, int L, const array<int, N>& T, array<int, N>& cnt) {\n    cnt.fill(0);\n    int cur = 0;\n    cnt[0] = 1;\n    for (int step = 1; step < L; ++step) {\n        int x = cur;\n        cur = (cnt[x] & 1) ? p.a[x] : p.b[x];\n        ++cnt[cur];\n    }\n    int E = 0;\n    for (int i = 0; i < N; ++i) E += iabs_int(cnt[i] - T[i]);\n    return E;\n}\n\n// Kosaraju SCC on \"core nodes\", edges are a[v], b[v] (assumed to be within core for v in core)\nint scc_core(const Plan& p, const vector<int>& core, const array<char, N>& inCore,\n             array<int, N>& compOut) {\n    vector<int> nodes = core;\n    int K = (int)nodes.size();\n    if (K == 0) return 0;\n    // map node -> idx not needed; use inCore check\n    vector<vector<int>> rg(N); rg.assign(N, {});\n    vector<vector<int>> g(N);  g.assign(N, {});\n    for (int v : nodes) {\n        int to1 = p.a[v], to2 = p.b[v];\n        g[v].push_back(to1);\n        g[v].push_back(to2);\n        rg[to1].push_back(v);\n        rg[to2].push_back(v);\n    }\n    vector<char> vis(N, 0);\n    vector<int> order; order.reserve(K);\n\n    auto dfs1 = [&](auto&& self, int v) -> void {\n        vis[v] = 1;\n        for (int to : g[v]) if (inCore[to] && !vis[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int v : nodes) if (!vis[v]) dfs1(dfs1, v);\n\n    compOut.fill(-1);\n    int compCnt = 0;\n    auto dfs2 = [&](auto&& self, int v) -> void {\n        compOut[v] = compCnt;\n        for (int to : rg[v]) if (inCore[to] && compOut[to] == -1) self(self, to);\n    };\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (compOut[v] == -1) {\n            dfs2(dfs2, v);\n            ++compCnt;\n        }\n    }\n    return compCnt;\n}\n\n// Static balance objective on core:\n// incomingW[j] = sum_{i in core} T[i] * [a_i==j] + T[i] * [b_i==j]\n// want incomingW[j] ~= 2*T[j]\nstruct StaticBalance {\n    array<long long, N> D; // D[j] = incomingW[j] - 2*T[j], only meaningful on core\n    long long F = 0;       // sum |D[j]| over core\n};\n\nStaticBalance compute_static_balance(const Plan& p, const array<int, N>& T,\n                                     const vector<int>& core, const array<char, N>& inCore) {\n    array<long long, N> incoming{};\n    incoming.fill(0);\n    for (int i : core) {\n        incoming[p.a[i]] += T[i];\n        incoming[p.b[i]] += T[i];\n    }\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = incoming[j] - 2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n    return sb;\n}\n\ninline long long delta_move_edge(long long Dold, long long Dnew, int w) {\n    // Move one edge of weight w: D_old -= w, D_new += w\n    long long before = iabs_ll(Dold) + iabs_ll(Dnew);\n    long long after  = iabs_ll(Dold - w) + iabs_ll(Dnew + w);\n    return after - before;\n}\n\ninline void apply_move_edge(StaticBalance& sb, int oldDest, int newDest, int w) {\n    // assumes oldDest,newDest are in core and w>=0\n    sb.F -= iabs_ll(sb.D[oldDest]);\n    sb.D[oldDest] -= w;\n    sb.F += iabs_ll(sb.D[oldDest]);\n\n    sb.F -= iabs_ll(sb.D[newDest]);\n    sb.D[newDest] += w;\n    sb.F += iabs_ll(sb.D[newDest]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, L;\n    cin >> Nin >> L;\n    array<int, N> T{};\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    uint64_t seed = 123456789ULL;\n    for (int i = 0; i < N; ++i) seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    RNG rng(seed);\n\n    auto time_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    // Core: nodes with positive target\n    array<char, N> inCore{};\n    inCore.fill(0);\n    vector<int> core;\n    core.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        if (T[i] > 0) { inCore[i] = 1; core.push_back(i); }\n    }\n\n    // Edge case: if somehow core is empty (shouldn't happen since sum T = L), make core {0}\n    if (core.empty()) { inCore[0] = 1; core.push_back(0); }\n\n    int hub = core[0];\n    for (int v : core) if (T[v] > T[hub]) hub = v;\n\n    Plan p;\n    p.a.fill(hub);\n    p.b.fill(hub);\n\n    // ----- Initial construction: greedy best-improvement per edge on static objective -----\n    // Initialize D = -2*T on core\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = -2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n\n    // Assign edges for core nodes to reduce F\n    for (int i : core) {\n        int w = T[i];\n        for (int e = 0; e < 2; ++e) {\n            int bestJ = core[rng.nextInt((int)core.size())];\n            long long bestDelta = (1LL<<62);\n\n            // If weight is 0 (shouldn't inside core), just random to help connectivity later\n            if (w == 0) {\n                bestJ = core[rng.nextInt((int)core.size())];\n                bestDelta = 0;\n            } else {\n                for (int j : core) {\n                    // currently edge points to hub, but we are building from scratch: treat as adding w to j\n                    long long before = iabs_ll(sb.D[j]);\n                    long long after  = iabs_ll(sb.D[j] + w);\n                    long long delta = after - before;\n                    if (delta < bestDelta || (delta == bestDelta && rng.nextInt(8) == 0)) {\n                        bestDelta = delta;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            // Apply: oldDest was \"none\" (incoming 0), but our sb.D already includes only demand.\n            // So just D[bestJ] += w, update F accordingly.\n            sb.F -= iabs_ll(sb.D[bestJ]);\n            sb.D[bestJ] += w;\n            sb.F += iabs_ll(sb.D[bestJ]);\n\n            if (e == 0) p.a[i] = bestJ;\n            else p.b[i] = bestJ;\n        }\n    }\n\n    // Non-core nodes: point to hub (won't be visited if core is closed and 0 in core; if 0 not in core, it is transient)\n    for (int i = 0; i < N; ++i) if (!inCore[i]) {\n        p.a[i] = hub;\n        p.b[i] = hub;\n    }\n\n    // If 0 is not in core, ensure it enters core immediately and never referenced by core (we keep core closed)\n    if (!inCore[0]) {\n        p.a[0] = hub;\n        p.b[0] = hub;\n    }\n\n    // Recompute sb properly from plan (for correctness after our incremental build)\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Fast SA on static balance objective -----\n    // Periodically keep sorted lists of deficits\n    vector<int> core_sorted = core;\n\n    auto resort_core = [&]() {\n        core_sorted = core;\n        sort(core_sorted.begin(), core_sorted.end(), [&](int x, int y) {\n            return sb.D[x] < sb.D[y]; // more negative first (needs incoming)\n        });\n    };\n    resort_core();\n\n    // Weighted source selection among core based on T[i]\n    vector<long long> pref;\n    pref.reserve(core.size()+1);\n    auto build_pref = [&]() {\n        pref.assign(core.size()+1, 0);\n        for (int k = 0; k < (int)core.size(); ++k) {\n            pref[k+1] = pref[k] + max(1, T[core[k]]); // avoid all-zero\n        }\n    };\n    build_pref();\n\n    auto pick_core_weighted = [&]() -> int {\n        long long sum = pref.back();\n        long long r = (long long)(rng.nextU64() % (uint64_t)sum);\n        int k = (int)(upper_bound(pref.begin(), pref.end(), r) - pref.begin()) - 1;\n        if (k < 0) k = 0;\n        if (k >= (int)core.size()) k = (int)core.size()-1;\n        return core[k];\n    };\n\n    const double STATIC_END = 0.65; // seconds budget for static stage\n    long long bestF = sb.F;\n    Plan bestStatic = p;\n\n    int iter = 0;\n    while (elapsedSec() < STATIC_END && !core.empty()) {\n        ++iter;\n        if ((iter & 1023) == 0) resort_core();\n\n        int i = (rng.nextInt(100) < 75) ? pick_core_weighted() : core[rng.nextInt((int)core.size())];\n        int w = T[i];\n        int e = rng.nextInt(2);\n        int& edge = (e == 0 ? p.a[i] : p.b[i]);\n        int oldDest = edge;\n\n        // choose new destination among a small candidate set\n        int candCount = 10;\n        long long bestDelta = (1LL<<62);\n        int bestDest = oldDest;\n\n        for (int t = 0; t < candCount; ++t) {\n            int newDest;\n            if (rng.nextInt(100) < 75) {\n                // pick from most-negative (needs incoming)\n                int idx = rng.nextInt(min(20, (int)core_sorted.size()));\n                newDest = core_sorted[idx];\n            } else {\n                newDest = core[rng.nextInt((int)core.size())];\n            }\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d < bestDelta) { bestDelta = d; bestDest = newDest; }\n        }\n        if (bestDest == oldDest) continue;\n\n        // SA acceptance on static objective\n        double tcur = min(1.0, elapsedSec() / STATIC_END);\n        double temp = 2000.0 * pow(1.0 / 2000.0, tcur); // 2000 -> 1\n        bool accept = false;\n        if (bestDelta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)bestDelta / temp)) accept = true;\n\n        if (!accept) continue;\n\n        // apply\n        apply_move_edge(sb, oldDest, bestDest, w);\n        edge = bestDest;\n\n        if (sb.F < bestF) {\n            bestF = sb.F;\n            bestStatic = p;\n        }\n    }\n    p = bestStatic;\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Repair: make core strongly connected (to avoid falling into a sink SCC subset) -----\n    array<int, N> comp{};\n    int compCnt = scc_core(p, core, inCore, comp);\n    int repairRounds = 0;\n    while (compCnt > 1 && elapsedSec() < 0.90 && repairRounds < 50) {\n        ++repairRounds;\n\n        vector<int> rep(compCnt, -1);\n        for (int v : core) {\n            int c = comp[v];\n            if (rep[c] == -1 || T[v] < T[rep[c]]) rep[c] = v;\n        }\n        // connect components in a cycle using minimal-static-delta edge rewires\n        for (int c = 0; c < compCnt; ++c) {\n            int from = rep[c];\n            int to = rep[(c+1) % compCnt];\n            if (from == -1 || to == -1) continue;\n            if (p.a[from] == to || p.b[from] == to) continue;\n\n            int w = T[from];\n\n            // choose whether to replace a or b to minimize static damage\n            long long da = delta_move_edge(sb.D[p.a[from]], sb.D[to], w);\n            long long db = delta_move_edge(sb.D[p.b[from]], sb.D[to], w);\n\n            if (da <= db) {\n                int old = p.a[from];\n                apply_move_edge(sb, old, to, w);\n                p.a[from] = to;\n            } else {\n                int old = p.b[from];\n                apply_move_edge(sb, old, to, w);\n                p.b[from] = to;\n            }\n        }\n\n        // small local clean-up on static objective after rewiring\n        for (int k = 0; k < 2000; ++k) {\n            int i = pick_core_weighted();\n            int w = T[i];\n            int e = rng.nextInt(2);\n            int& edge = (e == 0 ? p.a[i] : p.b[i]);\n            int oldDest = edge;\n\n            int newDest = core[rng.nextInt((int)core.size())];\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d <= 0) {\n                apply_move_edge(sb, oldDest, newDest, w);\n                edge = newDest;\n            }\n        }\n\n        compCnt = scc_core(p, core, inCore, comp);\n    }\n\n    // ----- Exact simulation SA on real objective -----\n    array<int, N> curCnt{}, bestCnt{}, tmpCnt{};\n    Plan curP = p, bestP = p;\n    int curE = simulate_plan(curP, L, T, curCnt);\n    int bestE = curE;\n    bestCnt = curCnt;\n\n    auto pick_x = [&]() -> int {\n        // choose among core (if 0 not in core, it is only visited once; no need to optimize edges by counts)\n        if (core.size() == 1) return core[0];\n        // rejection sampling biased by visit counts\n        int maxC = 1;\n        for (int v : core) maxC = max(maxC, curCnt[v]);\n        while (true) {\n            int v = core[rng.nextInt((int)core.size())];\n            if (rng.nextInt(maxC) < curCnt[v]) return v;\n        }\n    };\n\n    auto pick_dest_deficit = [&]() -> int {\n        // pick a destination in core biased to under-visited nodes\n        int maxD = 1;\n        for (int v : core) maxD = max(maxD, max(0, T[v] - curCnt[v]));\n        for (int tries = 0; tries < 50; ++tries) {\n            int v = core[rng.nextInt((int)core.size())];\n            int d = max(0, T[v] - curCnt[v]);\n            if (rng.nextInt(maxD) < d + 1) return v;\n        }\n        return core[rng.nextInt((int)core.size())];\n    };\n\n    auto core_strong_connected = [&](const Plan& pp) -> bool {\n        if (core.size() <= 1) return true;\n        // BFS from some start in core\n        int s = core[0];\n        vector<char> vis(N, 0);\n        deque<int> dq;\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            int to1 = pp.a[v], to2 = pp.b[v];\n            if (inCore[to1] && !vis[to1]) { vis[to1] = 1; dq.push_back(to1); }\n            if (inCore[to2] && !vis[to2]) { vis[to2] = 1; dq.push_back(to2); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n\n        // reverse BFS\n        vector<vector<int>> rg(N);\n        for (int v : core) {\n            rg[pp.a[v]].push_back(v);\n            rg[pp.b[v]].push_back(v);\n        }\n        fill(vis.begin(), vis.end(), 0);\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (int u : rg[v]) if (inCore[u] && !vis[u]) { vis[u] = 1; dq.push_back(u); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n        return true;\n    };\n\n    const double DYN_START = elapsedSec();\n    while (elapsedSec() < TIME_LIMIT) {\n        double t = (elapsedSec() - DYN_START) / max(1e-9, (TIME_LIMIT - DYN_START));\n        t = min(1.0, max(0.0, t));\n        double temp = 6000.0 * pow(30.0 / 6000.0, t);\n\n        int type = rng.nextInt(100);\n        int x1=-1, e1=0, old1=-1;\n        int x2=-1, e2=0, old2=-1;\n        int olda=-1, oldb=-1;\n\n        if (type < 72) {\n            // change one edge\n            x1 = pick_x();\n            e1 = rng.nextInt(2);\n            int& edge = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            old1 = edge;\n            int y = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y == old1) continue;\n            edge = y;\n        } else if (type < 92) {\n            // swap two edges\n            x1 = pick_x(); e1 = rng.nextInt(2);\n            x2 = pick_x(); e2 = rng.nextInt(2);\n            int& ed1 = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            int& ed2 = (e2==0 ? curP.a[x2] : curP.b[x2]);\n            old1 = ed1; old2 = ed2;\n            if (old1 == old2) continue;\n            ed1 = old2; ed2 = old1;\n        } else {\n            // reset both edges of one node\n            x1 = pick_x();\n            olda = curP.a[x1];\n            oldb = curP.b[x1];\n            int y1 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            int y2 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y1 == olda && y2 == oldb) continue;\n            curP.a[x1] = y1;\n            curP.b[x1] = y2;\n        }\n\n        // Keep core closed (should already hold by how we pick destinations), and keep core strongly connected\n        if (!core_strong_connected(curP)) {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n            continue;\n        }\n\n        int newE = simulate_plan(curP, L, T, tmpCnt);\n        int delta = newE - curE;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)delta / temp)) accept = true;\n\n        if (accept) {\n            curE = newE;\n            curCnt = tmpCnt;\n            if (curE < bestE) {\n                bestE = curE;\n                bestP = curP;\n                bestCnt = curCnt;\n            }\n        } else {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n        }\n    }\n\n    // Output best plan found\n    for (int i = 0; i < N; ++i) {\n        cout << bestP.a[i] << ' ' << bestP.b[i] << \"\\n\";\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\nusing namespace std;\n\nstruct City {\n    int lx, rx, ly, ry;\n    int cx, cy;\n    uint32_t morton;\n};\n\nstatic inline uint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nstatic inline uint32_t morton2D(uint32_t x, uint32_t y) {\n    return part1by1(x) | (part1by1(y) << 1);\n}\n\nstruct EdgeW {\n    int a, b;\n    uint16_t w;\n};\n\nstruct CandEdge {\n    int a, b;\n    uint16_t lb;   // rectangle lower bound\n    uint16_t cd;   // center distance\n    uint8_t tp;    // 0=query,1=neighbor,2=fallback\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    int ms() const {\n        return (int)chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<City> cities;\n    vector<uint16_t> distMat; // center dist floor euclid; N*N\n\n    Timer timer;\n    int q_used = 0;\n\n    vector<vector<int>> groups;\n    vector<vector<pair<int,int>>> queryEdges;\n    vector<char> fullQueried;\n\n    vector<vector<pair<int,int>>> fallbackEdges;\n    vector<vector<EdgeW>> fallbackEdgesW;\n    vector<long long> groupEstCost;\n\n    uint16_t dist_est(int a, int b) const { return distMat[a * N + b]; }\n\n    uint16_t rect_mindist(int a, int b) const {\n        const auto &A = cities[a];\n        const auto &B = cities[b];\n        long long dx = 0, dy = 0;\n        if (A.rx < B.lx) dx = (long long)B.lx - A.rx;\n        else if (B.rx < A.lx) dx = (long long)A.lx - B.rx;\n        if (A.ry < B.ly) dy = (long long)B.ly - A.ry;\n        else if (B.ry < A.ly) dy = (long long)A.ly - B.ry;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)floor(sqrt((double)sq));\n        d = max(0, min(65535, d));\n        return (uint16_t)d;\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int v : subset) cout << \" \" << v;\n        cout << \"\\n\" << flush;\n\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, l - 1));\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            cin >> a >> b;\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        q_used++;\n        return edges;\n    }\n\n    long long prim_build(const vector<int>& nodes, vector<pair<int,int>>* outEdges, vector<EdgeW>* outEdgesW) {\n        int s = (int)nodes.size();\n        if (outEdges) outEdges->clear();\n        if (outEdgesW) outEdgesW->clear();\n        if (s <= 1) return 0;\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        vector<uint16_t> minc(s, INF);\n        vector<int> parent(s, -1);\n        vector<char> used(s, false);\n\n        minc[0] = 0;\n        long long sum = 0;\n\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) if (!used[i]) {\n                if (v == -1 || minc[i] < minc[v]) v = i;\n            }\n            used[v] = true;\n\n            if (parent[v] != -1) {\n                int a = nodes[v], b = nodes[parent[v]];\n                uint16_t w = dist_est(a, b);\n                sum += (int)w;\n                if (a > b) swap(a, b);\n                if (outEdges) outEdges->push_back({a, b});\n                if (outEdgesW) outEdgesW->push_back({a, b, w});\n            }\n\n            int va = nodes[v];\n            for (int u = 0; u < s; u++) if (!used[u]) {\n                uint16_t d = dist_est(va, nodes[u]);\n                if (d < minc[u]) {\n                    minc[u] = d;\n                    parent[u] = v;\n                }\n            }\n        }\n        return sum;\n    }\n\n    long long eval_groups_mst(const vector<vector<int>>& gr) {\n        long long total = 0;\n        for (int k = 0; k < M; k++) total += prim_build(gr[k], nullptr, nullptr);\n        return total;\n    }\n\n    vector<vector<int>> build_groups_sweep(const vector<int>& order, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        int idx = 0;\n        for (int t = 0; t < M; t++) {\n            int k = groupOrder[t];\n            gr[k].reserve(G[k]);\n            for (int i = 0; i < G[k]; i++) gr[k].push_back(order[idx++]);\n        }\n        return gr;\n    }\n\n    vector<vector<int>> build_groups_grow(const vector<int>& seedOrder, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        vector<char> used(N, false);\n        vector<uint16_t> best(N);\n\n        int ptr = 0;\n        auto next_seed = [&]() -> int {\n            while (ptr < N && used[seedOrder[ptr]]) ptr++;\n            if (ptr >= N) {\n                for (int i = 0; i < N; i++) if (!used[i]) return i;\n                return -1;\n            }\n            return seedOrder[ptr];\n        };\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        for (int gid : groupOrder) {\n            int need = G[gid];\n            gr[gid].clear();\n            gr[gid].reserve(need);\n\n            int seed = next_seed();\n            if (seed < 0) break;\n            used[seed] = true;\n            gr[gid].push_back(seed);\n\n            for (int v = 0; v < N; v++) best[v] = used[v] ? INF : dist_est(seed, v);\n\n            for (int t = 1; t < need; t++) {\n                int pick = -1;\n                uint16_t bd = INF;\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = best[v];\n                    if (pick == -1 || d < bd) { bd = d; pick = v; }\n                }\n                if (pick < 0) break;\n                used[pick] = true;\n                gr[gid].push_back(pick);\n\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = dist_est(pick, v);\n                    if (d < best[v]) best[v] = d;\n                }\n            }\n        }\n        return gr;\n    }\n\n    // subset for edge (u,v): include u,v + nearest around each\n    vector<int> make_edge_subset(int k, int u, int v) {\n        const auto &nodes = groups[k];\n        int s = (int)nodes.size();\n        int want = min(L, s);\n        if (want < 3) return {u, v};\n\n        int rem = want - 2;\n        int a_take = rem / 2;\n        int b_take = rem - a_take;\n\n        vector<pair<uint16_t,int>> cu, cv;\n        cu.reserve(s);\n        cv.reserve(s);\n        for (int x : nodes) {\n            if (x == u || x == v) continue;\n            cu.emplace_back(dist_est(u, x), x);\n            cv.emplace_back(dist_est(v, x), x);\n        }\n        auto take_best = [&](vector<pair<uint16_t,int>>& c, int take) {\n            if (take <= 0) { c.clear(); return; }\n            if ((int)c.size() > take) {\n                nth_element(c.begin(), c.begin() + take, c.end());\n                c.resize(take);\n            }\n            sort(c.begin(), c.end());\n        };\n        take_best(cu, a_take);\n        take_best(cv, b_take);\n\n        vector<int> subset;\n        subset.reserve(want);\n        subset.push_back(u);\n        subset.push_back(v);\n\n        auto push_unique = [&](int x) {\n            for (int y : subset) if (y == x) return;\n            subset.push_back(x);\n        };\n        for (auto &p : cu) push_unique(p.second);\n        for (auto &p : cv) push_unique(p.second);\n\n        if ((int)subset.size() < want) {\n            vector<pair<uint16_t,int>> fill;\n            fill.reserve(s);\n            for (int x : nodes) {\n                bool ok = true;\n                for (int y : subset) if (y == x) { ok = false; break; }\n                if (!ok) continue;\n                uint16_t d = min(dist_est(u, x), dist_est(v, x));\n                fill.emplace_back(d, x);\n            }\n            int need = want - (int)subset.size();\n            if ((int)fill.size() > need) {\n                nth_element(fill.begin(), fill.begin() + need, fill.end());\n                fill.resize(need);\n            }\n            sort(fill.begin(), fill.end());\n            for (auto &p : fill) subset.push_back(p.second);\n        }\n        if ((int)subset.size() > want) subset.resize(want);\n        return subset;\n    }\n\n    static uint64_t subset_hash(vector<int> sub) {\n        sort(sub.begin(), sub.end());\n        uint64_t x = 1469598103934665603ULL;\n        for (int v : sub) {\n            x ^= (uint64_t)(v + 1);\n            x *= 1099511628211ULL;\n        }\n        return x;\n    }\n\n    // Sparse neighbor edges: connect next K in x/y/morton orders (O(s log s))\n    vector<pair<int,int>> build_neighbor_edges(const vector<int>& nodes, int Kwin) {\n        int s = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (s <= 1) return edges;\n        edges.reserve((size_t)s * Kwin * 3);\n\n        auto add_window = [&](vector<int>& ord) {\n            for (int i = 0; i < s; i++) {\n                int u = ord[i];\n                for (int d = 1; d <= Kwin && i + d < s; d++) {\n                    int v = ord[i + d];\n                    int a = u, b = v;\n                    if (a > b) swap(a, b);\n                    edges.emplace_back(a, b);\n                }\n            }\n        };\n\n        vector<int> ordx = nodes, ordy = nodes, ordm = nodes;\n        sort(ordx.begin(), ordx.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ordy.begin(), ordy.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ordm.begin(), ordm.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n\n        add_window(ordx);\n        add_window(ordy);\n        add_window(ordm);\n\n        sort(edges.begin(), edges.end());\n        edges.erase(unique(edges.begin(), edges.end()), edges.end());\n        return edges;\n    }\n\n    vector<pair<int,int>> build_final_tree(int k) {\n        const vector<int>& nodes = groups[k];\n        int s = (int)nodes.size();\n        if (s <= 1) return {};\n        if (s == 2) {\n            int a = nodes[0], b = nodes[1];\n            if (a > b) swap(a, b);\n            return {{a, b}};\n        }\n\n        if (fullQueried[k]) {\n            auto res = queryEdges[k];\n            if ((int)res.size() == s - 1) return res;\n        }\n\n        vector<int> pos(N, -1);\n        for (int i = 0; i < s; i++) pos[nodes[i]] = i;\n\n        auto norm_dedup = [&](vector<pair<int,int>>& es) {\n            for (auto &e : es) if (e.first > e.second) swap(e.first, e.second);\n            sort(es.begin(), es.end());\n            es.erase(unique(es.begin(), es.end()), es.end());\n        };\n\n        vector<pair<int,int>> qE = queryEdges[k];\n        vector<pair<int,int>> fb = fallbackEdges[k];\n        norm_dedup(qE);\n        norm_dedup(fb);\n\n        int Kwin = (s >= 180 ? 7 : (s >= 90 ? 5 : 4));\n        vector<pair<int,int>> nb = build_neighbor_edges(nodes, Kwin);\n        norm_dedup(nb);\n\n        vector<CandEdge> cand;\n        cand.reserve(qE.size() + nb.size() + fb.size());\n\n        auto add_list = [&](const vector<pair<int,int>>& es, uint8_t tp) {\n            for (auto &e : es) {\n                int a = e.first, b = e.second;\n                if (pos[a] < 0 || pos[b] < 0) continue;\n                cand.push_back({a, b, rect_mindist(a, b), dist_est(a, b), tp});\n            }\n        };\n\n        add_list(qE, 0);\n        add_list(nb, 1);\n        add_list(fb, 2);\n\n        sort(cand.begin(), cand.end(), [&](const CandEdge& A, const CandEdge& B){\n            if (A.tp != B.tp) return A.tp < B.tp;\n            if (A.lb != B.lb) return A.lb < B.lb;\n            if (A.cd != B.cd) return A.cd < B.cd;\n            if (A.a != B.a) return A.a < B.a;\n            return A.b < B.b;\n        });\n\n        atcoder::dsu dsu(s);\n        vector<pair<int,int>> res;\n        res.reserve(s - 1);\n\n        for (auto &e : cand) {\n            int pa = pos[e.a], pb = pos[e.b];\n            if (pa < 0 || pb < 0) continue;\n            if (dsu.same(pa, pb)) continue;\n            dsu.merge(pa, pb);\n            int a = e.a, b = e.b;\n            if (a > b) swap(a, b);\n            res.emplace_back(a, b);\n            if ((int)res.size() == s - 1) break;\n        }\n\n        if ((int)res.size() != s - 1) {\n            res = fb;\n            if ((int)res.size() != s - 1) {\n                res.clear();\n                for (int i = 1; i < s; i++) {\n                    int a = nodes[i-1], b = nodes[i];\n                    if (a > b) swap(a, b);\n                    res.emplace_back(a, b);\n                }\n            }\n        }\n        return res;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        cities.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto &c = cities[i];\n            cin >> c.lx >> c.rx >> c.ly >> c.ry;\n            c.cx = (c.lx + c.rx) / 2;\n            c.cy = (c.ly + c.ry) / 2;\n            uint32_t x = (uint32_t)min(16383, max(0, c.cx));\n            uint32_t y = (uint32_t)min(16383, max(0, c.cy));\n            c.morton = morton2D(x, y);\n        }\n\n        // Precompute center distances\n        distMat.assign((size_t)N * N, 0);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                long long dx = cities[i].cx - cities[j].cx;\n                long long dy = cities[i].cy - cities[j].cy;\n                long long sq = dx * dx + dy * dy;\n                int d = (int)floor(sqrt((double)sq));\n                d = max(0, min(65535, d));\n                distMat[i * N + j] = (uint16_t)d;\n                distMat[j * N + i] = (uint16_t)d;\n            }\n        }\n\n        // Deterministic RNG from rectangles\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < N; i++) {\n            seed ^= (uint64_t)cities[i].lx + 10007ULL * (uint64_t)cities[i].ly + 1000003ULL * (uint64_t)cities[i].rx;\n            seed *= 1099511628211ULL;\n        }\n        mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n        // Global base orders\n        vector<int> ord_m(N), ord_x(N), ord_y(N), ord_xy1(N), ord_xy2(N);\n        iota(ord_m.begin(), ord_m.end(), 0);\n        iota(ord_x.begin(), ord_x.end(), 0);\n        iota(ord_y.begin(), ord_y.end(), 0);\n        iota(ord_xy1.begin(), ord_xy1.end(), 0);\n        iota(ord_xy2.begin(), ord_xy2.end(), 0);\n\n        sort(ord_m.begin(), ord_m.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_x.begin(), ord_x.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_y.begin(), ord_y.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ord_xy1.begin(), ord_xy1.end(), [&](int a, int b){\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            return a < b;\n        });\n        sort(ord_xy2.begin(), ord_xy2.end(), [&](int a, int b){\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n\n        // Add 2 sampled-point morton orders as extra diversity (but still chosen by MST proxy)\n        auto make_sampled_morton_order = [&]() {\n            vector<pair<uint32_t,int>> tmp;\n            tmp.reserve(N);\n            for (int i = 0; i < N; i++) {\n                uniform_int_distribution<int> dx(cities[i].lx, cities[i].rx);\n                uniform_int_distribution<int> dy(cities[i].ly, cities[i].ry);\n                int x = dx(rng), y = dy(rng);\n                uint32_t key = morton2D((uint32_t)min(16383, max(0, x)), (uint32_t)min(16383, max(0, y)));\n                tmp.push_back({key, i});\n            }\n            sort(tmp.begin(), tmp.end(), [&](auto &A, auto &B){\n                if (A.first != B.first) return A.first < B.first;\n                return A.second < B.second;\n            });\n            vector<int> ord; ord.reserve(N);\n            for (auto &p : tmp) ord.push_back(p.second);\n            return ord;\n        };\n        vector<int> ord_s1 = make_sampled_morton_order();\n        vector<int> ord_s2 = make_sampled_morton_order();\n\n        // Group orders\n        vector<int> go_given(M), go_desc(M);\n        iota(go_given.begin(), go_given.end(), 0);\n        iota(go_desc.begin(), go_desc.end(), 0);\n        sort(go_desc.begin(), go_desc.end(), [&](int a, int b){\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        // Candidates (close to the proven fast version + a bit of diversity)\n        vector<vector<vector<int>>> candidates;\n        candidates.reserve(16);\n\n        candidates.push_back(build_groups_sweep(ord_m, go_desc));\n        candidates.push_back(build_groups_sweep(ord_m, go_given));\n        candidates.push_back(build_groups_sweep(ord_x, go_given));\n        candidates.push_back(build_groups_sweep(ord_y, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy1, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy2, go_given));\n        candidates.push_back(build_groups_sweep(ord_s1, go_given));\n        candidates.push_back(build_groups_sweep(ord_s2, go_given));\n\n        candidates.push_back(build_groups_grow(ord_m, go_desc));\n        candidates.push_back(build_groups_grow(ord_m, go_given));\n        candidates.push_back(build_groups_grow(ord_x, go_desc));\n        candidates.push_back(build_groups_grow(ord_y, go_desc));\n\n        for (int t = 0; t < 2; t++) {\n            vector<int> go = go_desc;\n            shuffle(go.begin(), go.end(), rng);\n            candidates.push_back(build_groups_grow(ord_m, go));\n        }\n\n        // Select best by estimated MST sum (no shortlist; stable)\n        long long bestScore = (1LL<<62);\n        int bestIdx = 0;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            long long sc = eval_groups_mst(candidates[i]);\n            if (sc < bestScore) { bestScore = sc; bestIdx = i; }\n        }\n        groups = move(candidates[bestIdx]);\n\n        // Build fallback MST for each group\n        fallbackEdges.assign(M, {});\n        fallbackEdgesW.assign(M, {});\n        groupEstCost.assign(M, 0);\n        for (int k = 0; k < M; k++) {\n            groupEstCost[k] = prim_build(groups[k], &fallbackEdges[k], &fallbackEdgesW[k]);\n        }\n\n        // ---- Queries (stable edge-focused plan) ----\n        queryEdges.assign(M, {});\n        fullQueried.assign(M, false);\n        q_used = 0;\n\n        auto time_ok = [&](){ return timer.ms() <= 1650; };\n\n        int num_large = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) num_large++;\n\n        int reserve_for_large = 0;\n        if (num_large > 0) {\n            reserve_for_large = min(Q, max(60, min(Q * 2 / 3, num_large * 10)));\n        }\n        int small_query_limit = max(0, Q - reserve_for_large);\n\n        vector<int> small;\n        for (int k = 0; k < M; k++) {\n            int s = (int)groups[k].size();\n            if (s >= 3 && s <= L) small.push_back(k);\n        }\n        sort(small.begin(), small.end(), [&](int a, int b){\n            int sa = (int)groups[a].size(), sb = (int)groups[b].size();\n            if (sa != sb) return sa > sb;\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return a < b;\n        });\n\n        for (int k : small) {\n            if (!time_ok()) break;\n            if (q_used >= small_query_limit) break;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        vector<int> large;\n        long long totalLargeCost = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) {\n            large.push_back(k);\n            totalLargeCost += groupEstCost[k];\n        }\n        sort(large.begin(), large.end(), [&](int a, int b){\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return (int)groups[a].size() > (int)groups[b].size();\n        });\n\n        unordered_set<uint64_t> usedSub;\n        usedSub.reserve(512);\n\n        for (int k : large) {\n            if (!time_ok() || q_used >= Q) break;\n\n            int remaining = Q - q_used;\n            int myBudget = 10;\n            if (totalLargeCost > 0) {\n                myBudget = (int)llround((double)reserve_for_large * (double)groupEstCost[k] / (double)totalLargeCost);\n            }\n            myBudget = max(4, min(myBudget, 16));\n            myBudget = min(myBudget, remaining);\n\n            auto edgesW = fallbackEdgesW[k];\n            sort(edgesW.begin(), edgesW.end(), [&](const EdgeW& A, const EdgeW& B){ return A.w > B.w; });\n\n            int qi = 0;\n            int takeEdges = min((int)edgesW.size(), myBudget * 3);\n            for (int i = 0; i < takeEdges && qi < myBudget && q_used < Q; i++) {\n                if (!time_ok()) break;\n                int u = edgesW[i].a, v = edgesW[i].b;\n                auto subset = make_edge_subset(k, u, v);\n                if ((int)subset.size() < 3) continue;\n\n                uint64_t hsub = subset_hash(subset);\n                if (usedSub.count(hsub)) continue;\n                usedSub.insert(hsub);\n\n                auto e = do_query(subset);\n                queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                qi++;\n            }\n        }\n\n        // Use leftover queries on remaining small groups (time-limited)\n        for (int k : small) {\n            if (!time_ok() || q_used >= Q) break;\n            if (fullQueried[k]) continue;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        // ---- Output ----\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            auto edges = build_final_tree(k);\n            int need = (int)groups[k].size() - 1;\n            if ((int)edges.size() != need) edges = fallbackEdges[k];\n\n            for (auto &e : edges) {\n                int a = e.first, b = e.second;\n                if (a > b) swap(a, b);\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout << flush;\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action { char a, d; };\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dirc[4] = {'U','D','L','R'};\nstatic const char actc[3] = {'M','S','A'};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n};\n\nstruct Solver {\n    int N, M;\n    vector<pair<int,int>> P;\n    int ord[20][20];\n\n    static constexpr int NN = 400;\n    static constexpr int KMAX = 13;\n    static constexpr int MAX_BLOCKS = 120;\n    static constexpr int EXTRA_BUDGET = 3;\n    static constexpr double TIME_LIMIT = 1.92;\n    static constexpr int MULTI_START_MAX = 3;\n\n    static constexpr int MAX_STATES = NN * (1 << KMAX);\n    vector<int16_t> distBuf;\n    vector<int32_t> prevBuf;\n    vector<uint8_t> prevOpBuf;\n    vector<int> visitedStates;\n    vector<int> q;\n    vector<uint8_t> popAll;\n\n    using Clock = chrono::steady_clock;\n    Clock::time_point t0;\n\n    Solver() {\n        distBuf.assign(MAX_STATES, -1);\n        prevBuf.resize(MAX_STATES);\n        prevOpBuf.resize(MAX_STATES);\n        visitedStates.reserve(1<<20);\n        q.reserve(1<<20);\n\n        popAll.assign(1<<KMAX, 0);\n        for (int m = 1; m < (1<<KMAX); m++) popAll[m] = popAll[m>>1] + (m&1);\n\n        for(int i=0;i<20;i++) for(int j=0;j<20;j++) ord[i][j]=-1;\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(Clock::now() - t0).count();\n    }\n\n    inline bool inside(int x,int y) const { return 0<=x && x<N && 0<=y && y<N; }\n    inline int posId(int x,int y) const { return x*N + y; }\n    inline pair<int,int> idPos(int id) const { return {id/N, id%N}; }\n\n    inline bool forbiddenCell(int x,int y,int curIndex) const {\n        int t = ord[x][y];\n        return (t != -1 && t > curIndex); // current/future targets forbidden\n    }\n    inline bool pastTargetCell(int x,int y,int curIndex) const {\n        int t = ord[x][y];\n        return (t != -1 && t <= curIndex);\n    }\n\n    // ---- fixed BFS (Move+Slide) ----\n    inline int slideStop(const uint8_t b[20][20], int x, int y, int dir) const {\n        int nx=x, ny=y;\n        while(true){\n            int tx=nx+di[dir], ty=ny+dj[dir];\n            if(!inside(tx,ty)) break;\n            if(b[tx][ty]) break;\n            nx=tx; ny=ty;\n        }\n        return posId(nx,ny);\n    }\n\n    int shortestFixedLen(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S=posId(s.first,s.second);\n        int G=posId(g.first,g.second);\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> qq;\n        int head=0, tail=0;\n        dist[S]=0; qq[tail++]=S;\n        while(head<tail){\n            int v=qq[head++];\n            if(v==G) return dist[v];\n            auto [x,y]=idPos(v);\n            for(int d=0; d<4; d++){\n                int mx=x+di[d], my=y+dj[d];\n                if(inside(mx,my) && !b[mx][my]){\n                    int to=posId(mx,my);\n                    if(dist[to]==-1){ dist[to]=dist[v]+1; qq[tail++]=to; }\n                }\n                int to=slideStop(b,x,y,d);\n                if(to!=v && dist[to]==-1){ dist[to]=dist[v]+1; qq[tail++]=to; }\n            }\n        }\n        return 1e9;\n    }\n\n    vector<Action> shortestFixedPath(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S=posId(s.first,s.second);\n        int G=posId(g.first,g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> prev;\n        prev.fill(-1);\n        array<uint8_t, NN> prevOp;\n        prevOp.fill(255);\n\n        array<int, NN> qq;\n        int head=0, tail=0;\n\n        dist[S]=0; qq[tail++]=S;\n        while(head<tail){\n            int v=qq[head++];\n            if(v==G) break;\n            auto [x,y]=idPos(v);\n\n            for(int d=0; d<4; d++){\n                int mx=x+di[d], my=y+dj[d];\n                if(inside(mx,my) && !b[mx][my]){\n                    int to=posId(mx,my);\n                    if(dist[to]==-1){\n                        dist[to]=dist[v]+1;\n                        prev[to]=v;\n                        prevOp[to]=(0*4+d);\n                        qq[tail++]=to;\n                    }\n                }\n                int to=slideStop(b,x,y,d);\n                if(to!=v && dist[to]==-1){\n                    dist[to]=dist[v]+1;\n                    prev[to]=v;\n                    prevOp[to]=(1*4+d);\n                    qq[tail++]=to;\n                }\n            }\n        }\n        if(dist[G]==-1) return {};\n\n        vector<Action> res;\n        for(int cur=G; cur!=S; cur=prev[cur]){\n            uint8_t code=prevOp[cur];\n            int a=code/4, d=code%4;\n            res.push_back(Action{actc[a], dirc[d]});\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    // ---- apply action ----\n    inline void applyAction(uint8_t b[20][20], int &totBlocks, pair<int,int> &cur, const Action &ac) const {\n        int d=0; while(d<4 && dirc[d]!=ac.d) d++;\n        int x=cur.first, y=cur.second;\n        if(ac.a=='M'){\n            cur={x+di[d], y+dj[d]};\n        }else if(ac.a=='S'){\n            int nx=x, ny=y;\n            while(true){\n                int tx=nx+di[d], ty=ny+dj[d];\n                if(!inside(tx,ty)) break;\n                if(b[tx][ty]) break;\n                nx=tx; ny=ty;\n            }\n            cur={nx,ny};\n        }else{ // 'A'\n            int ax=x+di[d], ay=y+dj[d];\n            if(!inside(ax,ay)) return;\n            bool before=b[ax][ay];\n            b[ax][ay]^=1;\n            if(!before && b[ax][ay]) totBlocks++;\n            if(before && !b[ax][ay]) totBlocks--;\n        }\n    }\n\n    // ---- connectivity check (plain move BFS) ----\n    bool allRemainingReachable(const uint8_t b[20][20], pair<int,int> startPos, int lastVisitedIndex) const {\n        static int vis[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) vis[i][j]=0;\n\n        if(b[startPos.first][startPos.second]) return false;\n\n        deque<pair<int,int>> dq;\n        vis[startPos.first][startPos.second]=1;\n        dq.push_back(startPos);\n\n        while(!dq.empty()){\n            auto [x,y]=dq.front(); dq.pop_front();\n            for(int d=0; d<4; d++){\n                int nx=x+di[d], ny=y+dj[d];\n                if(!inside(nx,ny)) continue;\n                if(vis[nx][ny]) continue;\n                if(b[nx][ny]) continue;\n                vis[nx][ny]=1;\n                dq.push_back({nx,ny});\n            }\n        }\n\n        for(int idx = lastVisitedIndex+1; idx < M; idx++){\n            auto [tx,ty]=P[idx];\n            if(!vis[tx][ty]) return false;\n        }\n        return true;\n    }\n\n    inline int blockPenaltyScaled2(int totBlocks) const {\n        if(totBlocks <= 100) return 0;\n        return (totBlocks - 100) * 2;\n    }\n\n    // Baseline slide blocker cells (beyond stop points)\n    void addBaselineSlideBlockers(const uint8_t b[20][20], pair<int,int> s,\n                                 const vector<Action>& basePath,\n                                 int curIndex, int pr[20][20]) const {\n        auto addCand = [&](int x,int y,int p){\n            if(!inside(x,y)) return;\n            if(forbiddenCell(x,y,curIndex)) return;\n            if(pastTargetCell(x,y,curIndex)) p += 25;\n            pr[x][y] = max(pr[x][y], p);\n        };\n\n        pair<int,int> cur = s;\n        for(const auto &ac: basePath){\n            int d=0; while(d<4 && dirc[d]!=ac.d) d++;\n            if(ac.a=='S'){\n                int nx=cur.first, ny=cur.second;\n                while(true){\n                    int tx=nx+di[d], ty=ny+dj[d];\n                    if(!inside(tx,ty)) break;\n                    if(b[tx][ty]) break;\n                    nx=tx; ny=ty;\n                }\n                int bx = nx + di[d], by = ny + dj[d];\n                // moderate priority so it doesn't crowd out goal neighborhood\n                addCand(bx, by, 110);\n                cur = {nx, ny};\n            } else if(ac.a=='M') {\n                cur = {cur.first + di[d], cur.second + dj[d]};\n            }\n        }\n    }\n\n    // local BFS: returns plan and objective (smaller better); INT_MAX if none\n    pair<vector<Action>, int> bestLocalPlan2Step(\n        SplitMix64 &rng,\n        int curIndex,\n        const uint8_t baseB[20][20],\n        int baseTotalBlocks,\n        pair<int,int> s, pair<int,int> g,\n        const vector<Action>& basePath,\n        bool has2, pair<int,int> t2,\n        bool has3, pair<int,int> t3,\n        int baselineObjScaled2\n    ){\n        if (basePath.empty()) return {{}, INT_MAX};\n        int baselineLen = (int)basePath.size();\n        if (baselineLen <= 1) return {{}, INT_MAX};\n        if (elapsed() > TIME_LIMIT) return {{}, INT_MAX};\n\n        int pr[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) pr[i][j]=-1;\n\n        auto noise = [&](int x,int y)->int{\n            uint64_t h = (uint64_t)(x*31 + y*131 + 0x9e3779b9);\n            h ^= rng.x + 0xD1B54A32D192ED03ULL;\n            h ^= (h<<7) ^ (h>>9);\n            return (int)(h % 7) - 3;\n        };\n\n        auto addCand = [&](int x,int y,int p){\n            if(!inside(x,y)) return;\n            if(forbiddenCell(x,y,curIndex)) return;\n            if(pastTargetCell(x,y,curIndex)) p += 35;\n            p += noise(x,y);\n            pr[x][y]=max(pr[x][y], p);\n        };\n\n        int sx=s.first, sy=s.second, gx=g.first, gy=g.second;\n\n        // Around goal\n        for(int d=0; d<4; d++){\n            addCand(gx+di[d], gy+dj[d], 240);\n            addCand(gx+2*di[d], gy+2*dj[d], 170);\n        }\n        for(int dx=-3; dx<=3; dx++) for(int dy=-3; dy<=3; dy++){\n            if(abs(dx)+abs(dy)<=3) addCand(gx+dx, gy+dy, 135);\n        }\n\n        // Around start\n        for(int d=0; d<4; d++) addCand(sx+di[d], sy+dj[d], 150);\n        for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n            if(abs(dx)+abs(dy)<=2) addCand(sx+dx, sy+dy, 100);\n        }\n\n        // L corners\n        int c1x=sx, c1y=gy;\n        int c2x=gx, c2y=sy;\n        for(int dx=-1; dx<=1; dx++) for(int dy=-1; dy<=1; dy++){\n            addCand(c1x+dx, c1y+dy, 125);\n            addCand(c2x+dx, c2y+dy, 125);\n        }\n\n        // Existing blocks near start/goal\n        for(int dx=-3; dx<=3; dx++) for(int dy=-3; dy<=3; dy++){\n            int x=gx+dx, y=gy+dy;\n            if(inside(x,y) && baseB[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x,y,150);\n        }\n        for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n            int x=sx+dx, y=sy+dy;\n            if(inside(x,y) && baseB[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x,y,110);\n        }\n\n        // Future hints\n        auto addFuture = [&](pair<int,int> t, int base){\n            int x=t.first, y=t.second;\n            for(int d=0; d<4; d++) addCand(x+di[d], y+dj[d], base);\n            for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n                if(abs(dx)+abs(dy)<=2) addCand(x+dx, y+dy, base-25);\n            }\n        };\n        if(has2) addFuture(t2, 70);\n        if(has3) addFuture(t3, 55);\n\n        // Minimal extra: baseline slide blocker cells (moderate priority)\n        addBaselineSlideBlockers(baseB, s, basePath, curIndex, pr);\n\n        struct C{int p,x,y;};\n        vector<C> cand;\n        cand.reserve(250);\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(pr[i][j]>=0) cand.push_back({pr[i][j],i,j});\n        if(cand.empty()) return {{}, INT_MAX};\n\n        sort(cand.begin(), cand.end(), [&](const C& a, const C& b){\n            if(a.p!=b.p) return a.p>b.p;\n            int mx=(sx+gx)/2, my=(sy+gy)/2;\n            int da=abs(a.x-mx)+abs(a.y-my);\n            int db=abs(b.x-mx)+abs(b.y-my);\n            if(da!=db) return da<db;\n            if(a.x!=b.x) return a.x<b.x;\n            return a.y<b.y;\n        });\n\n        int K=min((int)cand.size(), KMAX);\n        cand.resize(K);\n        int MSZ=1<<K;\n\n        int idx[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) idx[i][j]=-1;\n        for(int t=0;t<K;t++) idx[cand[t].x][cand[t].y]=t;\n\n        int initMask=0;\n        for(int t=0;t<K;t++) if(baseB[cand[t].x][cand[t].y]) initMask |= (1<<t);\n        int baseOutside = baseTotalBlocks - popAll[initMask];\n\n        auto sid = [&](int mask,int pos){ return mask*NN + pos; };\n\n        auto isBlocked = [&](int x,int y,int mask)->bool{\n            if(!inside(x,y)) return true;\n            int t=idx[x][y];\n            if(t>=0) return (mask>>t)&1;\n            return baseB[x][y];\n        };\n\n        auto slideStopMask = [&](int x,int y,int dir,int mask)->int{\n            int nx=x, ny=y;\n            while(true){\n                int tx=nx+di[dir], ty=ny+dj[dir];\n                if(!inside(tx,ty)) break;\n                if(isBlocked(tx,ty,mask)) break;\n                nx=tx; ny=ty;\n            }\n            return posId(nx,ny);\n        };\n\n        int Spos=posId(s.first,s.second);\n        int Gpos=posId(g.first,g.second);\n        int limit = baselineLen + EXTRA_BUDGET;\n\n        visitedStates.clear();\n        q.clear();\n\n        auto pushState = [&](int id,int16_t d,int32_t parent,uint8_t op){\n            distBuf[id]=d;\n            prevBuf[id]=parent;\n            prevOpBuf[id]=op;\n            visitedStates.push_back(id);\n            q.push_back(id);\n        };\n\n        int s0 = sid(initMask, Spos);\n        pushState(s0, 0, -1, 255);\n\n        size_t head=0;\n        while(head<q.size()){\n            int v=q[head++];\n            int16_t dcur=distBuf[v];\n            if(dcur>=limit) continue;\n\n            int mask=v/NN;\n            int pos=v%NN;\n            auto [x,y]=idPos(pos);\n\n            // Move/Slide\n            for(int dd=0; dd<4; dd++){\n                int mx=x+di[dd], my=y+dj[dd];\n                if(inside(mx,my) && !isBlocked(mx,my,mask)){\n                    int to=sid(mask, posId(mx,my));\n                    if(distBuf[to]==-1) pushState(to, dcur+1, v, (0*4+dd));\n                }\n                int sp=slideStopMask(x,y,dd,mask);\n                if(sp!=pos){\n                    int to=sid(mask, sp);\n                    if(distBuf[to]==-1) pushState(to, dcur+1, v, (1*4+dd));\n                }\n            }\n\n            // Alter adjacent candidate only\n            for(int dd=0; dd<4; dd++){\n                int ax=x+di[dd], ay=y+dj[dd];\n                if(!inside(ax,ay)) continue;\n                int t=idx[ax][ay];\n                if(t<0) continue;\n                if(forbiddenCell(ax,ay,curIndex)) continue;\n\n                int nmask = mask ^ (1<<t);\n                int totTemp = baseOutside + popAll[nmask];\n                if(totTemp > MAX_BLOCKS) continue;\n\n                int to=sid(nmask, pos);\n                if(distBuf[to]==-1) pushState(to, dcur+1, v, (2*4+dd));\n            }\n        }\n\n        uint8_t tempB[20][20];\n\n        int bestObj = baselineObjScaled2;\n        int bestId = -1;\n        int bestD1 = INT_MAX;\n        int bestBlocks = INT_MAX;\n\n        for(int mask=0; mask<MSZ; mask++){\n            int id=sid(mask, Gpos);\n            int16_t d1=distBuf[id];\n            if(d1==-1 || d1>limit) continue;\n\n            memcpy(tempB, baseB, sizeof(tempB));\n            for(int t=0;t<K;t++) tempB[cand[t].x][cand[t].y] = (mask>>t)&1;\n\n            int d2=0, d3=0;\n            if(has2) d2 = shortestFixedLen(tempB, g, t2);\n            if(has3) d3 = shortestFixedLen(tempB, t2, t3);\n\n            int totBlocksTemp = baseOutside + popAll[mask];\n            int obj = 2*((int)d1 + d2) + d3 + blockPenaltyScaled2(totBlocksTemp);\n\n            if(obj < bestObj ||\n               (obj==bestObj && (int)d1 < bestD1) ||\n               (obj==bestObj && (int)d1==bestD1 && totBlocksTemp < bestBlocks)){\n                bestObj = obj;\n                bestId = id;\n                bestD1 = (int)d1;\n                bestBlocks = totBlocksTemp;\n            }\n        }\n\n        vector<Action> res;\n        if(bestId != -1 && bestObj <= baselineObjScaled2){\n            int curId = bestId;\n            while(curId != s0){\n                uint8_t code = prevOpBuf[curId];\n                int a=code/4, d=code%4;\n                res.push_back(Action{actc[a], dirc[d]});\n                curId = prevBuf[curId];\n                if(curId < 0) break;\n            }\n            reverse(res.begin(), res.end());\n        }\n\n        for(int id: visitedStates) distBuf[id] = -1;\n\n        if(res.empty()) return {{}, INT_MAX};\n        return {res, bestObj};\n    }\n\n    struct RunResult {\n        vector<Action> acts;\n        int visited = 0;\n        int turns = 0;\n    };\n\n    RunResult solveOne(uint64_t seed) {\n        SplitMix64 rng(seed);\n\n        uint8_t b[20][20];\n        memset(b, 0, sizeof(b));\n        int totBlocks = 0;\n\n        pair<int,int> cur = P[0];\n        vector<Action> out;\n        out.reserve(700);\n\n        int visited = 0;\n\n        for(int k=0; k<M-1; k++){\n            if ((int)out.size() >= 2*N*M) break;\n\n            if (elapsed() > TIME_LIMIT) {\n                // finish greedily\n                for(int kk=k; kk<M-1; kk++){\n                    auto path = shortestFixedPath(b, cur, P[kk+1]);\n                    if(path.empty()) break;\n                    for(auto &ac: path){\n                        out.push_back(ac);\n                        applyAction(b, totBlocks, cur, ac);\n                        if ((int)out.size() >= 2*N*M) break;\n                    }\n                    if(cur == P[kk+1]) visited++;\n                    if ((int)out.size() >= 2*N*M) break;\n                }\n                break;\n            }\n\n            pair<int,int> goal = P[k+1];\n            bool has2 = (k+2 < M);\n            bool has3 = (k+3 < M);\n            pair<int,int> t2 = has2 ? P[k+2] : make_pair(-1,-1);\n            pair<int,int> t3 = has3 ? P[k+3] : make_pair(-1,-1);\n\n            auto basePath = shortestFixedPath(b, cur, goal);\n            if(basePath.empty()) break;\n            int baseLen = (int)basePath.size();\n\n            int d2=0, d3=0;\n            if(has2) d2 = shortestFixedLen(b, goal, t2);\n            if(has3) d3 = shortestFixedLen(b, t2, t3);\n            int baseObj = 2*(baseLen + d2) + d3 + blockPenaltyScaled2(totBlocks);\n\n            auto [locPlan, locObj] = bestLocalPlan2Step(\n                rng, k, b, totBlocks, cur, goal, basePath, has2, t2, has3, t3, baseObj\n            );\n\n            const vector<Action>* use = &basePath;\n\n            // validate local plan (reach goal + block cap + connectivity)\n            if(!locPlan.empty() && locObj <= baseObj){\n                uint8_t tb[20][20];\n                memcpy(tb, b, sizeof(tb));\n                int tBlocks = totBlocks;\n                pair<int,int> tcur = cur;\n\n                for(auto &ac: locPlan) applyAction(tb, tBlocks, tcur, ac);\n\n                bool ok = true;\n                if(tcur != goal) ok = false;\n                if(tBlocks > MAX_BLOCKS) ok = false;\n                if(ok && !allRemainingReachable(tb, tcur, k+1)) ok = false;\n\n                if(ok){\n                    if(locObj < baseObj || (locObj==baseObj && (int)locPlan.size() < baseLen)){\n                        use = &locPlan;\n                    }\n                }\n            }\n\n            for(auto &ac: *use){\n                out.push_back(ac);\n                applyAction(b, totBlocks, cur, ac);\n                if ((int)out.size() >= 2*N*M) break;\n            }\n\n            if(cur == goal) visited++;\n            else break;\n        }\n\n        RunResult rr;\n        rr.acts = std::move(out);\n        rr.visited = visited;\n        rr.turns = (int)rr.acts.size();\n        return rr;\n    }\n\n    void solve() {\n        t0 = Clock::now();\n\n        RunResult best = solveOne(0x123456789abcdef0ULL);\n\n        int tries = 1;\n        while (tries < MULTI_START_MAX && elapsed() < 1.85) {\n            uint64_t seed =\n                0x9e3779b97f4a7c15ULL * (tries + 1) ^\n                (uint64_t)chrono::duration_cast<chrono::nanoseconds>(Clock::now().time_since_epoch()).count();\n            RunResult rr = solveOne(seed);\n\n            if (rr.visited > best.visited || (rr.visited == best.visited && rr.turns < best.turns)) {\n                best = std::move(rr);\n            }\n            tries++;\n        }\n\n        for (auto &ac : best.acts) {\n            cout << ac.a << ' ' << ac.d << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    cin >> s.N >> s.M;\n    s.P.resize(s.M);\n    for(int k=0;k<s.M;k++){\n        int x,y; cin >> x >> y;\n        s.P[k] = {x,y};\n        s.ord[x][y] = k;\n    }\n    s.solve();\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Rect { int a,b,c,d; }; // [a,c) x [b,d)\n\nstatic inline bool overlap1D(int l1,int r1,int l2,int r2){\n    return max(l1,l2) < min(r1,r2);\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now()-st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32(){ return (uint32_t)next_u64(); }\n    int rand_int(int l,int r){\n        if(l>r) return l;\n        uint64_t range=(uint64_t)(r-l+1);\n        return l + (int)(next_u64()%range);\n    }\n    double rand01(){ return (next_u64()>>11) * (1.0/9007199254740992.0); }\n};\n\nstruct PushGroup { int cnt=0; int ids[205]; int dmax=0; };\n\nstruct Candidate1D { int m,k; long long err; };\nstruct SplitChoice {\n    bool ok=false, vertical=false;\n    int k=0, m=0;\n    long long err=0;\n    vector<int> leftIds, rightIds;\n};\n\nstruct State {\n    vector<Rect> rect;\n    vector<double> p;\n    double sumP=0;\n};\n\nstruct RawCand { vector<Rect> rect; double score; };\n\nstruct Solver {\n    int n;\n    vector<int> x,y;\n    vector<long long> r;\n\n    vector<Rect> rect;\n    vector<double> p;\n    double sumP=0.0;\n\n    SplitMix64 rng;\n    Timer timer;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n); y.resize(n); r.resize(n);\n        for(int i=0;i<n;i++) cin >> x[i] >> y[i] >> r[i];\n\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = SplitMix64(seed);\n\n        rect.resize(n);\n        p.assign(n,0.0);\n\n        for(int i=0;i<n;i++) rect[i] = {x[i], y[i], x[i]+1, y[i]+1};\n        recompute_all_scores();\n    }\n\n    inline long long area(const Rect& R) const { return 1LL*(R.c-R.a)*(R.d-R.b); }\n    inline int width(const Rect& R)  const { return R.c-R.a; }\n    inline int height(const Rect& R) const { return R.d-R.b; }\n\n    inline bool contains_point(int i, const Rect& R) const {\n        return (R.a<=x[i] && x[i]<R.c && R.b<=y[i] && y[i]<R.d);\n    }\n\n    inline double satisfaction(int i, const Rect& R) const {\n        if(!contains_point(i, R)) return 0.0;\n        long long s = area(R), ri = r[i];\n        long long mn = min(ri, s), mx = max(ri, s);\n        double ratio = (double)mn / (double)mx;\n        double t = 1.0 - ratio;\n        return 1.0 - t*t;\n    }\n\n    void recompute_all_scores(){\n        sumP = 0.0;\n        for(int i=0;i<n;i++){\n            p[i] = satisfaction(i, rect[i]);\n            sumP += p[i];\n        }\n    }\n\n    State snapshot() const { return State{rect, p, sumP}; }\n    void restore(const State& s){ rect=s.rect; p=s.p; sumP=s.sumP; }\n\n    // pick worst p among k random\n    inline int pick_bad_rect(int k){\n        int best = (int)(rng.next_u32()%n);\n        double bestScore = p[best];\n        for(int t=1;t<k;t++){\n            int i = (int)(rng.next_u32()%n);\n            if(p[i] < bestScore){\n                bestScore = p[i];\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    inline int pick_rect_for_sa(){\n        double u = rng.rand01();\n        if(u < 0.65) return pick_bad_rect(5);\n        if(u < 0.90) return pick_bad_rect(3);\n        return (int)(rng.next_u32()%n);\n    }\n\n    // ===== single-side move =====\n    // dir: 0=a(left),1=c(right),2=b(down),3=d(up)\n    bool feasible_range(int i,int dir,int &low,int &high) const {\n        const Rect &R = rect[i];\n        if(dir==0 || dir==1){\n            int leftLimit=0, rightLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q = rect[j];\n                if(!overlap1D(R.b,R.d,Q.b,Q.d)) continue;\n                if(Q.c<=R.a) leftLimit=max(leftLimit,Q.c);\n                if(R.c<=Q.a) rightLimit=min(rightLimit,Q.a);\n            }\n            if(dir==0){ low=leftLimit; high=min(x[i], R.c-1); }\n            else { low=max(x[i]+1, R.a+1); high=rightLimit; }\n        }else{\n            int downLimit=0, upLimit=10000;\n            for(int j=0;j<n;j++) if(j!=i){\n                const Rect &Q = rect[j];\n                if(!overlap1D(R.a,R.c,Q.a,Q.c)) continue;\n                if(Q.d<=R.b) downLimit=max(downLimit,Q.d);\n                if(R.d<=Q.b) upLimit=min(upLimit,Q.b);\n            }\n            if(dir==2){ low=downLimit; high=min(y[i], R.d-1); }\n            else { low=max(y[i]+1, R.b+1); high=upLimit; }\n        }\n        return low<=high;\n    }\n\n    int desired_side_value(int i,int dir,int low,int high) const {\n        const Rect& R = rect[i];\n        long long ri = r[i];\n        if(dir==0 || dir==1){\n            int h = height(R);\n            long long desiredW = (ri + h/2)/h;\n            desiredW = max<long long>(1, min<long long>(10000, desiredW));\n            if(dir==0){\n                long long desA = (long long)R.c - desiredW;\n                return (int)max<long long>(low, min<long long>(high, desA));\n            }else{\n                long long desC = (long long)R.a + desiredW;\n                return (int)max<long long>(low, min<long long>(high, desC));\n            }\n        }else{\n            int w = width(R);\n            long long desiredH = (ri + w/2)/w;\n            desiredH = max<long long>(1, min<long long>(10000, desiredH));\n            if(dir==2){\n                long long desB = (long long)R.d - desiredH;\n                return (int)max<long long>(low, min<long long>(high, desB));\n            }else{\n                long long desD = (long long)R.b + desiredH;\n                return (int)max<long long>(low, min<long long>(high, desD));\n            }\n        }\n    }\n\n    static inline Rect with_side(Rect R,int dir,int val){\n        if(dir==0) R.a=val;\n        else if(dir==1) R.c=val;\n        else if(dir==2) R.b=val;\n        else R.d=val;\n        return R;\n    }\n\n    bool greedy_improve_one_side(int i){\n        double cur=p[i], best=cur;\n        Rect bestR=rect[i];\n\n        for(int dir=0;dir<4;dir++){\n            int low,high;\n            if(!feasible_range(i,dir,low,high)) continue;\n            int curVal = (dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n            if(low==high && low==curVal) continue;\n\n            int des=desired_side_value(i,dir,low,high);\n            int cand[3]={des,low,high};\n            for(int v: cand){\n                if(v<low||v>high||v==curVal) continue;\n                Rect R2=with_side(rect[i],dir,v);\n                if(R2.a>=R2.c || R2.b>=R2.d) continue;\n                double sc=satisfaction(i,R2);\n                if(sc>best+1e-12){ best=sc; bestR=R2; }\n            }\n        }\n\n        if(best>cur+1e-12){\n            rect[i]=bestR;\n            sumP += (best - p[i]);\n            p[i]=best;\n            return true;\n        }\n        return false;\n    }\n\n    // ===== group push (touching-only), cap=dmax =====\n    bool compute_push_group(int i,int dir, PushGroup &pg) const {\n        pg.cnt=0; pg.dmax=0;\n        const Rect &I=rect[i];\n\n        if(dir==1){\n            int pos1=10001, pos2=10001;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ak=R.a;\n                if(ak<I.c) continue;\n                if(ak<pos1){ pos2=pos1; pos1=ak; pg.cnt=0; pg.ids[pg.cnt++]=k; }\n                else if(ak==pos1){ pg.ids[pg.cnt++]=k; }\n                else if(ak<pos2){ pos2=ak; }\n            }\n            if(pos1==10001 || pos1!=I.c) return false;\n            if(pos2==10001) pos2=10000;\n            int expandMax=min(10000-I.c, pos2-I.c);\n            int shrinkMax=INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int lim=min(x[k], R.c-1) - R.a;\n                shrinkMax=min(shrinkMax, lim);\n            }\n            pg.dmax=max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n\n        if(dir==0){\n            int pos1=-1, pos2=-1;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.b,I.d,R.b,R.d)) continue;\n                int ck=R.c;\n                if(ck>I.a) continue;\n                if(ck>pos1){ pos2=pos1; pos1=ck; pg.cnt=0; pg.ids[pg.cnt++]=k; }\n                else if(ck==pos1){ pg.ids[pg.cnt++]=k; }\n                else if(ck>pos2){ pos2=ck; }\n            }\n            if(pos1==-1 || pos1!=I.a) return false;\n            if(pos2==-1) pos2=0;\n            int expandMax=I.a-pos2;\n            int shrinkMax=INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int need=max(x[k]+1, R.a+1);\n                int lim=R.c-need;\n                shrinkMax=min(shrinkMax, lim);\n            }\n            pg.dmax=max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n\n        if(dir==3){\n            int pos1=10001, pos2=10001;\n            for(int k=0;k<n;k++) if(k!=i){\n                const Rect &R=rect[k];\n                if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n                int bk=R.b;\n                if(bk<I.d) continue;\n                if(bk<pos1){ pos2=pos1; pos1=bk; pg.cnt=0; pg.ids[pg.cnt++]=k; }\n                else if(bk==pos1){ pg.ids[pg.cnt++]=k; }\n                else if(bk<pos2){ pos2=bk; }\n            }\n            if(pos1==10001 || pos1!=I.d) return false;\n            if(pos2==10001) pos2=10000;\n            int expandMax=min(10000-I.d, pos2-I.d);\n            int shrinkMax=INT_MAX;\n            for(int t=0;t<pg.cnt;t++){\n                int k=pg.ids[t];\n                const Rect &R=rect[k];\n                int lim=min(y[k], R.d-1) - R.b;\n                shrinkMax=min(shrinkMax, lim);\n            }\n            pg.dmax=max(0, min(expandMax, shrinkMax));\n            return pg.dmax>0;\n        }\n\n        // dir==2\n        int pos1=-1, pos2=-1;\n        for(int k=0;k<n;k++) if(k!=i){\n            const Rect &R=rect[k];\n            if(!overlap1D(I.a,I.c,R.a,R.c)) continue;\n            int dk=R.d;\n            if(dk>I.b) continue;\n            if(dk>pos1){ pos2=pos1; pos1=dk; pg.cnt=0; pg.ids[pg.cnt++]=k; }\n            else if(dk==pos1){ pg.ids[pg.cnt++]=k; }\n            else if(dk>pos2){ pos2=dk; }\n        }\n        if(pos1==-1 || pos1!=I.b) return false;\n        if(pos2==-1) pos2=0;\n        int expandMax=I.b-pos2;\n        int shrinkMax=INT_MAX;\n        for(int t=0;t<pg.cnt;t++){\n            int k=pg.ids[t];\n            const Rect &R=rect[k];\n            int need=max(y[k]+1, R.b+1);\n            int lim=R.d-need;\n            shrinkMax=min(shrinkMax, lim);\n        }\n        pg.dmax=max(0, min(expandMax, shrinkMax));\n        return pg.dmax>0;\n    }\n\n    inline void apply_group_push(int i,int dir,const PushGroup &pg,int delta){\n        if(dir==1){ rect[i].c += delta; for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].a += delta; }\n        else if(dir==0){ rect[i].a -= delta; for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].c -= delta; }\n        else if(dir==3){ rect[i].d += delta; for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].b += delta; }\n        else { rect[i].b -= delta; for(int t=0;t<pg.cnt;t++) rect[pg.ids[t]].d -= delta; }\n    }\n\n    bool greedy_improve_push_group(int i){\n        double bestGain=0.0;\n        int bestDir=-1, bestDelta=0;\n        PushGroup bestPg;\n\n        for(int dir=0;dir<4;dir++){\n            PushGroup pg;\n            if(!compute_push_group(i,dir,pg)) continue;\n            int cap = pg.dmax;\n\n            long long ai=area(rect[i]);\n            long long deficit=r[i]-ai;\n            long long per=(dir==0||dir==1)?(long long)height(rect[i]):(long long)width(rect[i]);\n            int desd=1;\n            if(deficit>0) desd=(int)min<long long>(cap, max<long long>(1, (deficit+per-1)/per));\n\n            int cand[7] = { 1, cap, max(1, cap/2), desd, min(cap, desd*2), max(1, desd/2), max(1, cap/max(1,pg.cnt)) };\n            sort(cand, cand+7);\n            int m=0;\n            for(int t=0;t<7;t++) if(t==0 || cand[t]!=cand[t-1]) cand[m++]=cand[t];\n\n            for(int t=0;t<m;t++){\n                int delta=cand[t];\n                if(delta<1||delta>cap) continue;\n\n                Rect oldI=rect[i];\n                double oldPi=p[i];\n                Rect oldR[205];\n                double oldP[205];\n                double oldSum=oldPi;\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    oldR[u]=rect[k];\n                    oldP[u]=p[k];\n                    oldSum += oldP[u];\n                }\n\n                apply_group_push(i,dir,pg,delta);\n\n                double newSum = satisfaction(i,rect[i]);\n                for(int u=0;u<pg.cnt;u++){\n                    int k=pg.ids[u];\n                    newSum += satisfaction(k,rect[k]);\n                }\n\n                rect[i]=oldI;\n                for(int u=0;u<pg.cnt;u++) rect[pg.ids[u]]=oldR[u];\n\n                double gain=newSum-oldSum;\n                if(gain > bestGain + 1e-12){\n                    bestGain=gain;\n                    bestDir=dir;\n                    bestDelta=delta;\n                    bestPg=pg;\n                }\n            }\n        }\n\n        if(bestGain > 1e-12){\n            double oldSum = p[i];\n            for(int u=0;u<bestPg.cnt;u++) oldSum += p[bestPg.ids[u]];\n\n            apply_group_push(i,bestDir,bestPg,bestDelta);\n\n            double newSum=0.0;\n            p[i]=satisfaction(i,rect[i]); newSum+=p[i];\n            for(int u=0;u<bestPg.cnt;u++){\n                int k=bestPg.ids[u];\n                p[k]=satisfaction(k,rect[k]);\n                newSum+=p[k];\n            }\n            sumP += (newSum-oldSum);\n            return true;\n        }\n        return false;\n    }\n\n    inline bool greedy_step(int i){\n        if(area(rect[i]) < r[i]) {\n            if(greedy_improve_push_group(i)) return true;\n            return greedy_improve_one_side(i);\n        } else {\n            if(greedy_improve_one_side(i)) return true;\n            return greedy_improve_push_group(i);\n        }\n    }\n\n    void quick_greedy(int steps){\n        for(int it=0; it<steps; it++){\n            int i = (rng.rand01()<0.85) ? pick_bad_rect(4) : (int)(rng.next_u32()%n);\n            greedy_step(i);\n        }\n    }\n\n    // ===== BSP init =====\n    SplitChoice best_vertical_split(int a,int b,int c,int d, const vector<int>& ids){\n        SplitChoice sc;\n        int w=c-a;\n        if(w<=1 || ids.size()<=1) return sc;\n\n        vector<int> ord=ids;\n        sort(ord.begin(), ord.end(), [&](int i,int j){\n            if(x[i]!=x[j]) return x[i]<x[j];\n            return y[i]<y[j];\n        });\n\n        int sz=(int)ord.size();\n        vector<long long> prefSum(sz+1,0);\n        vector<int> prefMaxX(sz+1,-1);\n        vector<int> sufMinX(sz+1, 100000);\n        for(int i=0;i<sz;i++){\n            prefSum[i+1]=prefSum[i]+r[ord[i]];\n            prefMaxX[i+1]=max(prefMaxX[i], x[ord[i]]);\n        }\n        for(int i=sz-1;i>=0;i--) sufMinX[i]=min(sufMinX[i+1], x[ord[i]]);\n        long long total=prefSum[sz];\n\n        vector<Candidate1D> cand;\n        cand.reserve(sz);\n        for(int m=1;m<sz;m++){\n            long long sumL=prefSum[m];\n            int lo=max(a+1, prefMaxX[m]+1);\n            int hi=min(c-1, sufMinX[m]);\n            if(lo>hi) continue;\n\n            long long numer=1LL*w*sumL;\n            int idealW=(int)((numer + total/2)/total);\n            idealW=max(1, min(w-1, idealW));\n            int k=a+idealW;\n            k=max(lo, min(hi, k));\n            int leftW=k-a;\n\n            long long err=llabs(1LL*leftW*total - 1LL*w*sumL);\n            cand.push_back({m,k,err});\n        }\n        if(cand.empty()) return sc;\n\n        sort(cand.begin(), cand.end(), [](const Candidate1D& A,const Candidate1D& B){ return A.err<B.err; });\n        int pickN=min(5,(int)cand.size());\n        int pickIdx=(rng.rand01()<0.25)?rng.rand_int(0,pickN-1):0;\n\n        sc.ok=true; sc.vertical=true;\n        sc.m=cand[pickIdx].m;\n        sc.k=cand[pickIdx].k;\n        sc.err=cand[pickIdx].err;\n        sc.leftIds.assign(ord.begin(), ord.begin()+sc.m);\n        sc.rightIds.assign(ord.begin()+sc.m, ord.end());\n        return sc;\n    }\n\n    SplitChoice best_horizontal_split(int a,int b,int c,int d, const vector<int>& ids){\n        SplitChoice sc;\n        int h=d-b;\n        if(h<=1 || ids.size()<=1) return sc;\n\n        vector<int> ord=ids;\n        sort(ord.begin(), ord.end(), [&](int i,int j){\n            if(y[i]!=y[j]) return y[i]<y[j];\n            return x[i]<x[j];\n        });\n\n        int sz=(int)ord.size();\n        vector<long long> prefSum(sz+1,0);\n        vector<int> prefMaxY(sz+1,-1);\n        vector<int> sufMinY(sz+1, 100000);\n        for(int i=0;i<sz;i++){\n            prefSum[i+1]=prefSum[i]+r[ord[i]];\n            prefMaxY[i+1]=max(prefMaxY[i], y[ord[i]]);\n        }\n        for(int i=sz-1;i>=0;i--) sufMinY[i]=min(sufMinY[i+1], y[ord[i]]);\n        long long total=prefSum[sz];\n\n        vector<Candidate1D> cand;\n        cand.reserve(sz);\n        for(int m=1;m<sz;m++){\n            long long sumD=prefSum[m];\n            int lo=max(b+1, prefMaxY[m]+1);\n            int hi=min(d-1, sufMinY[m]);\n            if(lo>hi) continue;\n\n            long long numer=1LL*h*sumD;\n            int idealH=(int)((numer + total/2)/total);\n            idealH=max(1, min(h-1, idealH));\n            int k=b+idealH;\n            k=max(lo, min(hi, k));\n            int downH=k-b;\n\n            long long err=llabs(1LL*downH*total - 1LL*h*sumD);\n            cand.push_back({m,k,err});\n        }\n        if(cand.empty()) return sc;\n\n        sort(cand.begin(), cand.end(), [](const Candidate1D& A,const Candidate1D& B){ return A.err<B.err; });\n        int pickN=min(5,(int)cand.size());\n        int pickIdx=(rng.rand01()<0.25)?rng.rand_int(0,pickN-1):0;\n\n        sc.ok=true; sc.vertical=false;\n        sc.m=cand[pickIdx].m;\n        sc.k=cand[pickIdx].k;\n        sc.err=cand[pickIdx].err;\n        sc.leftIds.assign(ord.begin(), ord.begin()+sc.m);\n        sc.rightIds.assign(ord.begin()+sc.m, ord.end());\n        return sc;\n    }\n\n    void bsp_build(int a,int b,int c,int d, const vector<int>& ids){\n        if(ids.size()==1){ rect[ids[0]]={a,b,c,d}; return; }\n        int w=c-a, h=d-b;\n\n        SplitChoice V=best_vertical_split(a,b,c,d,ids);\n        SplitChoice H=best_horizontal_split(a,b,c,d,ids);\n\n        SplitChoice chosen;\n        if(V.ok && H.ok){\n            long long vErr=V.err, hErr=H.err;\n            if(w>h) vErr=(vErr*97)/100;\n            else if(h>w) hErr=(hErr*97)/100;\n            if(rng.rand01()<0.08) chosen=(rng.rand01()<0.5?V:H);\n            else chosen=(vErr<=hErr?V:H);\n        }else if(V.ok) chosen=V;\n        else chosen=H;\n\n        if(chosen.vertical){\n            int k=chosen.k;\n            bsp_build(a,b,k,d, chosen.leftIds);\n            bsp_build(k,b,c,d, chosen.rightIds);\n        }else{\n            int k=chosen.k;\n            bsp_build(a,b,c,k, chosen.leftIds);\n            bsp_build(a,k,c,d, chosen.rightIds);\n        }\n    }\n\n    void init_1x1(){\n        for(int i=0;i<n;i++) rect[i]={x[i],y[i],x[i]+1,y[i]+1};\n        recompute_all_scores();\n    }\n    void init_bsp(){\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        bsp_build(0,0,10000,10000, ids);\n        recompute_all_scores();\n    }\n\n    // SA for a fixed deadline (keeps best within this run)\n    void simulated_annealing_until(double deadline){\n        vector<Rect> bestRect = rect;\n        vector<double> bestP = p;\n        double bestSum = sumP;\n\n        const double T0=0.16, T1=0.0021;\n        double startT = timer.elapsed();\n        double dur = max(1e-6, deadline - startT);\n        long long iters=0;\n        double T=T0;\n\n        while(true){\n            if((iters & 4095) == 0){\n                double now = timer.elapsed();\n                if(now >= deadline) break;\n                double prog = (now - startT) / dur;\n                prog = min(1.0, max(0.0, prog));\n                T = T0 * exp(log(T1/T0)*prog);\n            }\n            iters++;\n\n            int i = pick_rect_for_sa();\n            bool under = (area(rect[i]) < r[i]);\n            double pushProb = under ? 0.40 : 0.20;\n            bool doPush = (rng.rand01() < pushProb);\n\n            if(!doPush){\n                int dir1=(int)(rng.next_u32()&3), dir2=(int)(rng.next_u32()&3);\n                int low1,high1,low2,high2;\n                bool ok1=feasible_range(i,dir1,low1,high1);\n                bool ok2=feasible_range(i,dir2,low2,high2);\n                int dir=-1, low=0, high=0;\n                if(ok1 && ok2){\n                    if((high2-low2)>(high1-low1)){ dir=dir2; low=low2; high=high2; }\n                    else { dir=dir1; low=low1; high=high1; }\n                }else if(ok1){ dir=dir1; low=low1; high=high1; }\n                else if(ok2){ dir=dir2; low=low2; high=high2; }\n                else continue;\n\n                int curVal=(dir==0?rect[i].a:dir==1?rect[i].c:dir==2?rect[i].b:rect[i].d);\n                if(low==high) continue;\n\n                int des=desired_side_value(i,dir,low,high);\n                int candVal;\n                if(rng.rand01()<0.78){\n                    int span=max(1,(high-low)/8);\n                    candVal=des + rng.rand_int(-span, span);\n                    candVal=max(low, min(high, candVal));\n                }else candVal=rng.rand_int(low, high);\n                if(candVal==curVal) continue;\n\n                Rect oldR=rect[i];\n                double oldPi=p[i];\n                Rect newR=with_side(oldR,dir,candVal);\n                if(newR.a>=newR.c || newR.b>=newR.d) continue;\n\n                double newPi=satisfaction(i,newR);\n                double diff=newPi-oldPi;\n                if(diff>=0 || rng.rand01()<exp(diff/T)){\n                    rect[i]=newR; p[i]=newPi; sumP+=diff;\n                    if(sumP > bestSum + 1e-9){\n                        bestSum = sumP; bestRect = rect; bestP = p;\n                    }\n                }\n            }else{\n                int dirA=(int)(rng.next_u32()&3), dirB=(int)(rng.next_u32()&3);\n                PushGroup pgA, pgB;\n                bool okA=compute_push_group(i,dirA,pgA);\n                bool okB=compute_push_group(i,dirB,pgB);\n\n                int dir=-1; PushGroup pg;\n                if(okA && okB){\n                    if(pgB.dmax > pgA.dmax){ dir=dirB; pg=pgB; }\n                    else { dir=dirA; pg=pgA; }\n                }else if(okA){ dir=dirA; pg=pgA; }\n                else if(okB){ dir=dirB; pg=pgB; }\n                else continue;\n\n                int cap = pg.dmax;\n                if(cap<=0) continue;\n\n                long long deficit = r[i] - area(rect[i]);\n                long long per = (dir==0||dir==1)?(long long)height(rect[i]):(long long)width(rect[i]);\n                int desd=1;\n                if(deficit>0) desd=(int)min<long long>(cap, max<long long>(1, (deficit+per-1)/per));\n\n                int delta;\n                double u=rng.rand01();\n                if(u < 0.52){\n                    int span=max(1, cap/12);\n                    delta = desd + rng.rand_int(-span, span);\n                    delta = max(1, min(cap, delta));\n                }else if(u < 0.84){\n                    double t = rng.rand01();\n                    int d = (int)floor(exp(log((double)cap) * t) + 1e-9);\n                    delta = max(1, min(cap, d));\n                }else if(u < 0.90){\n                    delta = cap;\n                }else{\n                    delta = rng.rand_int(1, cap);\n                }\n\n                Rect oldI=rect[i];\n                double oldPi=p[i];\n                Rect oldR[205];\n                double oldPbuf[205];\n                double oldSum=oldPi;\n                for(int u2=0;u2<pg.cnt;u2++){\n                    int k=pg.ids[u2];\n                    oldR[u2]=rect[k];\n                    oldPbuf[u2]=p[k];\n                    oldSum += oldPbuf[u2];\n                }\n\n                apply_group_push(i,dir,pg,delta);\n\n                double newPi=satisfaction(i,rect[i]);\n                double newSum=newPi;\n                double newGroupP[205];\n                for(int u2=0;u2<pg.cnt;u2++){\n                    int k=pg.ids[u2];\n                    newGroupP[u2]=satisfaction(k,rect[k]);\n                    newSum += newGroupP[u2];\n                }\n\n                double diff=newSum-oldSum;\n                if(diff>=0 || rng.rand01()<exp(diff/T)){\n                    p[i]=newPi;\n                    for(int u2=0;u2<pg.cnt;u2++) p[pg.ids[u2]]=newGroupP[u2];\n                    sumP += diff;\n                    if(sumP > bestSum + 1e-9){\n                        bestSum = sumP; bestRect = rect; bestP = p;\n                    }\n                }else{\n                    rect[i]=oldI; p[i]=oldPi;\n                    for(int u2=0;u2<pg.cnt;u2++){\n                        int k=pg.ids[u2];\n                        rect[k]=oldR[u2];\n                        p[k]=oldPbuf[u2];\n                    }\n                }\n            }\n        }\n\n        rect = bestRect;\n        p = bestP;\n        sumP = bestSum;\n    }\n\n    // ===== solve pipeline =====\n    void solve(){\n        const double HARD_LIMIT = 4.95;\n        const double INIT_BUDGET = 1.15;\n\n        // keep top-3 heavy-polished candidates\n        vector<State> bestInits;\n\n        auto push_init_candidate = [&](const State& s){\n            bestInits.push_back(s);\n            sort(bestInits.begin(), bestInits.end(), [](const State& A,const State& B){ return A.sumP > B.sumP; });\n            if((int)bestInits.size() > 3) bestInits.resize(3);\n        };\n\n        // baseline\n        init_1x1();\n        quick_greedy(5000);\n        push_init_candidate(snapshot());\n\n        // BSP pool with medium greedy\n        vector<RawCand> pool;\n        pool.reserve(24);\n        int tries=0;\n        while(tries < 16 && timer.elapsed() < INIT_BUDGET){\n            init_bsp();\n            quick_greedy(2500);\n            pool.push_back({rect, sumP});\n            tries++;\n        }\n\n        if(!pool.empty()){\n            sort(pool.begin(), pool.end(), [](const RawCand& A,const RawCand& B){ return A.score > B.score; });\n            int K=min(4,(int)pool.size());\n            vector<int> chosen;\n            for(int i=0;i<K;i++) chosen.push_back(i);\n            if((int)pool.size() > K) chosen.push_back(rng.rand_int(K, (int)pool.size()-1)); // diversify\n\n            for(int idx: chosen){\n                rect = pool[idx].rect;\n                recompute_all_scores();\n                quick_greedy(8500);\n                push_init_candidate(snapshot());\n            }\n        }\n\n        if(bestInits.empty()) bestInits.push_back(snapshot());\n\n        // SA: probe + commit\n        double hardDeadline = HARD_LIMIT - 0.005;\n        double saDeadline   = HARD_LIMIT - 0.010; // leave a bit for final greedy+output\n        double now = timer.elapsed();\n\n        State globalBest = bestInits[0];\n\n        if(now < saDeadline - 0.05){\n            double remain = saDeadline - now;\n            int runs = (int)bestInits.size();\n            // fixed probe total fraction\n            double probeTotal = remain * 0.30;\n            double probeEach = probeTotal / runs;\n\n            State bestAfterProbe;\n            bestAfterProbe.sumP = -1e100;\n\n            for(int t=0;t<runs;t++){\n                restore(bestInits[t]);\n                double dl = min(saDeadline, timer.elapsed() + probeEach);\n                simulated_annealing_until(dl);\n                State res = snapshot();\n                if(res.sumP > bestAfterProbe.sumP) bestAfterProbe = res;\n                if(res.sumP > globalBest.sumP) globalBest = res;\n                if(timer.elapsed() >= saDeadline) break;\n            }\n\n            // commit\n            restore(bestAfterProbe);\n            simulated_annealing_until(saDeadline);\n            State finalSA = snapshot();\n            if(finalSA.sumP > globalBest.sumP) globalBest = finalSA;\n        }\n\n        restore(globalBest);\n\n        // cheap last-mile monotone improvement (worst-of-8), no sorting\n        while(timer.elapsed() < hardDeadline){\n            int i = pick_bad_rect(8);\n            greedy_step(i);\n            greedy_step(i);\n        }\n\n        for(int i=0;i<n;i++){\n            cout << rect[i].a << ' ' << rect[i].b << ' ' << rect[i].c << ' ' << rect[i].d << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50, W = 50, N = H * W;\nstatic constexpr int MAXM = 2500;\nstatic constexpr int BSZ = (MAXM + 63) / 64;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463325252ULL) {}\n    inline uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); } // inclusive\n};\n\nstruct TileSet {\n    array<uint64_t, BSZ> b{};\n    inline void clear() { b.fill(0); }\n    inline bool test(int i) const { return (b[i >> 6] >> (i & 63)) & 1ULL; }\n    inline void set1(int i) { b[i >> 6] |= (1ULL << (i & 63)); }\n    inline void reset1(int i) { b[i >> 6] &= ~(1ULL << (i & 63)); }\n};\n\nstruct Params {\n    double a1;       // square mobility weight\n    double a2;       // tile mobility weight\n    double a3;       // small optional 2-hop proxy (candidate tile only)\n    double g;        // 2-step lookahead weight\n    double deadPen;  // deg1==0 penalty\n    double p0, p1;   // pocket penalties by tile-degree\n};\n\nstruct State {\n    vector<int> path;      // squares\n    vector<int> tileStack; // tile ids parallel to path\n    TileSet used;\n    vector<uint8_t> cnt;   // reference count per tile (robust unmark)\n    int score = 0;\n\n    inline void init_cnt(int M) { cnt.assign(M, 0); }\n\n    inline bool usedTile(int t) const { return used.test(t); }\n\n    inline void addTile(int t) {\n        uint8_t &c = cnt[t];\n        if (c == 0) used.set1(t);\n        if (c != 255) c++;\n    }\n    inline void removeTile(int t) {\n        uint8_t &c = cnt[t];\n        if (c == 0) return; // should not happen\n        c--;\n        if (c == 0) used.reset1(t);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    cin >> si >> sj;\n    const int start = si * W + sj;\n\n    vector<int> tile(N);\n    int maxTile = 0;\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int t; cin >> t;\n        tile[i * W + j] = t;\n        maxTile = max(maxTile, t);\n    }\n    const int M = maxTile + 1;\n\n    vector<int> val(N);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int p; cin >> p;\n        val[i * W + j] = p;\n    }\n\n    // Square adjacency excluding same-tile moves\n    array<array<int, 4>, N> nbr;\n    array<uint8_t, N> deg{};\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        uint8_t d = 0;\n        auto add = [&](int ni, int nj) {\n            if (ni < 0 || ni >= H || nj < 0 || nj >= W) return;\n            int v = ni * W + nj;\n            if (tile[u] == tile[v]) return;\n            nbr[u][d++] = v;\n        };\n        add(i - 1, j); add(i + 1, j); add(i, j - 1); add(i, j + 1);\n        deg[u] = d;\n    }\n\n    // Tile adjacency graph\n    vector<vector<int>> tadj(M);\n    for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {\n        int u = i * W + j;\n        int tu = tile[u];\n        if (j + 1 < W) {\n            int v = i * W + (j + 1);\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n        if (i + 1 < H) {\n            int v = (i + 1) * W + j;\n            int tv = tile[v];\n            if (tu != tv) { tadj[tu].push_back(tv); tadj[tv].push_back(tu); }\n        }\n    }\n    for (int t = 0; t < M; t++) {\n        auto &v = tadj[t];\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n    }\n\n    auto deg_square = [&](int sq, const TileSet &used) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            if (!used.test(tile[to])) d++;\n        }\n        return d;\n    };\n    auto deg_square_forbid_tile = [&](int sq, const TileSet &used, int forbidTile) -> int {\n        int d = 0;\n        for (int k = 0; k < (int)deg[sq]; k++) {\n            int to = nbr[sq][k];\n            int tt = tile[to];\n            if (tt == forbidTile) continue;\n            if (!used.test(tt)) d++;\n        }\n        return d;\n    };\n    auto deg_tile_unvisited = [&](int t, const TileSet &used) -> int {\n        int d = 0;\n        for (int nx : tadj[t]) if (!used.test(nx)) d++;\n        return d;\n    };\n    // cheap 2-hop proxy (candidate only)\n    auto tile_2hop = [&](int t, const TileSet &used) -> int {\n        int s = 0;\n        for (int u : tadj[t]) {\n            if (used.test(u)) continue;\n            // degree of u excluding t (approx by counting neighbors != t)\n            int d = 0;\n            for (int v : tadj[u]) if (v != t && !used.test(v)) d++;\n            s += d;\n        }\n        return s;\n    };\n\n    auto eval_move = [&](int nxSq, const TileSet &used, const Params &P) -> double {\n        int dn1 = deg_square(nxSq, used);\n        int tn = tile[nxSq];\n        int dt = deg_tile_unvisited(tn, used);\n        int t2 = (P.a3 != 0.0 ? tile_2hop(tn, used) : 0);\n\n        // 2-step lookahead (do NOT use tile_2hop here for speed)\n        double best2 = 0.0;\n        for (int k = 0; k < (int)deg[nxSq]; k++) {\n            int nn = nbr[nxSq][k];\n            int tnn = tile[nn];\n            if (used.test(tnn)) continue;\n            int d2 = deg_square_forbid_tile(nn, used, tn);\n            int dt2 = deg_tile_unvisited(tnn, used); // slightly optimistic but ok\n            double s2 = val[nn] + P.a1 * d2 + 0.50 * P.a2 * dt2;\n            if (s2 > best2) best2 = s2;\n        }\n\n        double sc = val[nxSq] + P.a1 * dn1 + P.a2 * dt + P.a3 * t2 + P.g * best2;\n        if (dt == 0) sc -= P.p0;\n        else if (dt == 1) sc -= P.p1;\n        if (dn1 == 0) sc -= P.deadPen;\n        return sc;\n    };\n\n    auto pick_next = [&](State &st, XorShift64 &rng, const Params &P) -> int {\n        int cur = st.path.back();\n\n        int cand[4], cm = 0;\n        for (int k = 0; k < (int)deg[cur]; k++) {\n            int to = nbr[cur][k];\n            if (!st.usedTile(tile[to])) cand[cm++] = to;\n        }\n        if (cm == 0) return -1;\n\n        // avoid immediate dead-end if possible\n        int d1[4];\n        bool anyNonDead = false;\n        for (int i = 0; i < cm; i++) {\n            d1[i] = deg_square(cand[i], st.used);\n            if (d1[i] > 0) anyNonDead = true;\n        }\n\n        struct Item { int sq; double sc; };\n        Item items[4];\n        int im = 0;\n        for (int i = 0; i < cm; i++) {\n            if (anyNonDead && d1[i] == 0) continue;\n            double sc = eval_move(cand[i], st.used, P) + rng.next_double() * 1e-3;\n            items[im++] = {cand[i], sc};\n        }\n        if (im == 0) return -1;\n\n        for (int i = 0; i < im; i++) {\n            int best = i;\n            for (int j = i + 1; j < im; j++) if (items[j].sc > items[best].sc) best = j;\n            swap(items[i], items[best]);\n        }\n\n        int pick = 0;\n        double u = rng.next_double();\n        if (im >= 2) {\n            if (u < 0.80) pick = 0;\n            else if (u < 0.95) pick = 1;\n            else pick = min(2, im - 1);\n        }\n        return items[pick].sq;\n    };\n\n    auto extend_greedy = [&](State &st, XorShift64 &rng, const Params &P) {\n        while (true) {\n            int nxt = pick_next(st, rng, P);\n            if (nxt < 0) break;\n            int tnx = tile[nxt];\n            st.addTile(tnx);\n            st.path.push_back(nxt);\n            st.tileStack.push_back(tnx);\n            st.score += val[nxt];\n        }\n    };\n\n    auto random_params = [&](XorShift64 &rng) -> Params {\n        Params P;\n        P.a1 = 7.0 + 20.0 * rng.next_double();\n        P.a2 = 1.0 + 11.0 * rng.next_double();\n        P.a3 = 0.0;\n        if (rng.next_double() < 0.35) P.a3 = 0.10 + 0.90 * rng.next_double(); // [0.10,1.00]\n        P.g  = 0.08 + 0.62 * rng.next_double();\n        P.deadPen = 22.0 + 55.0 * rng.next_double();\n        P.p0 = 18.0 + 45.0 * rng.next_double();\n        P.p1 =  5.0 + 25.0 * rng.next_double();\n        return P;\n    };\n\n    auto build_one = [&](XorShift64 &rng) -> State {\n        State st;\n        st.used.clear();\n        st.init_cnt(M);\n        st.path.reserve(N);\n        st.tileStack.reserve(N);\n\n        st.path.push_back(start);\n        st.tileStack.push_back(tile[start]);\n        st.addTile(tile[start]);\n        st.score = val[start];\n\n        Params P = random_params(rng);\n        extend_greedy(st, rng, P);\n        return st;\n    };\n\n    auto rebuild_cur_from_best = [&](State &cur, const vector<int> &bestPath) {\n        cur.used.clear();\n        cur.init_cnt(M);\n        cur.path = bestPath;\n        cur.tileStack.clear();\n        cur.tileStack.reserve(bestPath.size());\n        cur.score = 0;\n        for (int sq : bestPath) {\n            int t = tile[sq];\n            cur.tileStack.push_back(t);\n            cur.addTile(t);\n            cur.score += val[sq];\n        }\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto now = [&]() { return chrono::steady_clock::now(); };\n    const double TL = 1.88; // safety margin\n\n    XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Multi-start init\n    State cur = build_one(rng);\n    vector<int> bestPath = cur.path;\n    int bestScore = cur.score;\n\n    while (chrono::duration<double>(now() - t0).count() < 0.30) {\n        State s = build_one(rng);\n        if (s.score > bestScore) {\n            bestScore = s.score;\n            bestPath = s.path;\n        }\n    }\n    rebuild_cur_from_best(cur, bestPath);\n\n    vector<int> removedSq, removedTile;\n    removedSq.reserve(N);\n    removedTile.reserve(N);\n\n    int it = 0;\n    while (true) {\n        double elapsed = chrono::duration<double>(now() - t0).count();\n        if (elapsed > TL) break;\n        it++;\n\n        if (it % 2600 == 0) {\n            rebuild_cur_from_best(cur, bestPath);\n        }\n\n        int L = (int)cur.path.size();\n        if (L <= 1) continue;\n\n        // cut distribution\n        int k;\n        double r = rng.next_double();\n        if (r < 0.03) k = 0;\n        else if (r < 0.15) k = rng.next_int(0, L - 2);\n        else if (r < 0.75) {\n            int lo = max(0, L - 1 - 260);\n            k = rng.next_int(lo, L - 2);\n        } else {\n            int lo = max(0, L - 1 - 700);\n            k = rng.next_int(lo, L - 2);\n        }\n\n        int origScore = cur.score;\n\n        removedSq.clear();\n        removedTile.clear();\n\n        // cut to k+1\n        while ((int)cur.path.size() > k + 1) {\n            int sq = cur.path.back(); cur.path.pop_back();\n            int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n            cur.removeTile(tid);\n            cur.score -= val[sq];\n            removedSq.push_back(sq);\n            removedTile.push_back(tid);\n        }\n\n        Params P = random_params(rng);\n        extend_greedy(cur, rng, P);\n\n        int delta = cur.score - origScore;\n\n        // SA acceptance\n        elapsed = chrono::duration<double>(now() - t0).count();\n        double tr = min(1.0, elapsed / TL);\n        double T0 = 420.0, Tend = 2.0;\n        double T = T0 * pow(Tend / T0, tr);\n\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            // remove regrown part\n            while ((int)cur.path.size() > k + 1) {\n                int sq = cur.path.back(); cur.path.pop_back();\n                int tid = cur.tileStack.back(); cur.tileStack.pop_back();\n                cur.removeTile(tid);\n                cur.score -= val[sq];\n            }\n            // restore old suffix\n            for (int i = (int)removedSq.size() - 1; i >= 0; i--) {\n                int sq = removedSq[i];\n                int tid = removedTile[i];\n                cur.path.push_back(sq);\n                cur.tileStack.push_back(tid);\n                cur.addTile(tid);\n                cur.score += val[sq];\n            }\n        } else {\n            if (cur.score > bestScore) {\n                bestScore = cur.score;\n                bestPath = cur.path; // copy path only\n            }\n        }\n    }\n\n    // Final validation & truncation (hard safety net)\n    vector<char> usedT(M, 0);\n    vector<int> validPath;\n    validPath.reserve(bestPath.size());\n    validPath.push_back(start);\n    usedT[tile[start]] = 1;\n\n    for (int idx = 1; idx < (int)bestPath.size(); idx++) {\n        int a = validPath.back();\n        int b = bestPath[idx];\n\n        // adjacency check\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (abs(ai - bi) + abs(aj - bj) != 1) break;\n\n        // tile repeat check\n        int tb = tile[b];\n        if (usedT[tb]) break;\n        usedT[tb] = 1;\n        validPath.push_back(b);\n    }\n\n    // Output directions\n    string out;\n    out.reserve(validPath.size() ? validPath.size() - 1 : 0);\n    for (int i = 1; i < (int)validPath.size(); i++) {\n        int a = validPath[i - 1], b = validPath[i];\n        int ai = a / W, aj = a % W;\n        int bi = b / W, bj = b % W;\n        if (bi == ai - 1 && bj == aj) out.push_back('U');\n        else if (bi == ai + 1 && bj == aj) out.push_back('D');\n        else if (bi == ai && bj == aj - 1) out.push_back('L');\n        else if (bi == ai && bj == aj + 1) out.push_back('R');\n        else break;\n    }\n    cout << out << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct EdgeRef {\n    bool horiz; // true: horizontal h[i][j], false: vertical v[i][j]\n    int i, j;\n};\n\nstatic constexpr int N = 30;\nstatic constexpr int HW = 29;\nstatic constexpr int VH = 29;\n\nstruct PathInfo {\n    vector<int> nodes;\n    vector<EdgeRef> edges;\n    string moves;\n    double base_sum = 0.0; // sum of raw current weights along path (for learning/prediction)\n};\n\nstruct Solver {\n    // raw per-edge weights (what we learn)\n    double h[N][HW];\n    double v[VH][N];\n    int hc[N][HW];\n    int vc[VH][N];\n\n    // planning priors (log-mean) per row/col computed from visited edges\n    double rowLogMean[N];\n    double colLogMean[N];\n\n    vector<EdgeRef> last_edges;\n    double last_pred = 1.0;\n    int k = 0;\n\n    Solver() {\n        for (int i = 0; i < N; i++) {\n            rowLogMean[i] = log(5000.0);\n            colLogMean[i] = log(5000.0);\n        }\n        for (int i = 0; i < N; i++) for (int j = 0; j < HW; j++) {\n            h[i][j] = 5000.0;\n            hc[i][j] = 0;\n        }\n        for (int i = 0; i < VH; i++) for (int j = 0; j < N; j++) {\n            v[i][j] = 5000.0;\n            vc[i][j] = 0;\n        }\n    }\n\n    static inline double clampd(double x, double lo, double hi) {\n        return (x < lo) ? lo : (x > hi) ? hi : x;\n    }\n\n    inline double &wref(const EdgeRef &e) { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int &cref(const EdgeRef &e) { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n    inline double wval(const EdgeRef &e) const { return e.horiz ? h[e.i][e.j] : v[e.i][e.j]; }\n    inline int cval(const EdgeRef &e) const { return e.horiz ? hc[e.i][e.j] : vc[e.i][e.j]; }\n\n    inline EdgeRef edgeBetween(int u, int w) const {\n        int ui = u / N, uj = u % N;\n        int wi = w / N, wj = w % N;\n        if (ui == wi) {\n            if (wj == uj + 1) return {true, ui, uj};\n            else return {true, ui, wj};\n        } else {\n            if (wi == ui + 1) return {false, ui, uj};\n            else return {false, wi, uj};\n        }\n    }\n\n    inline double rawEdgeWeight(const EdgeRef &e) const {\n        return clampd(wval(e), 500.0, 12000.0);\n    }\n\n    // compute row/col log-means using only visited edges (cnt>0)\n    void updateLineMeans() {\n        for (int i = 0; i < N; i++) {\n            double sw = 0.0, sy = 0.0;\n            for (int j = 0; j < HW; j++) {\n                int c = hc[i][j];\n                if (c <= 0) continue;\n                double w = clampd(h[i][j], 500.0, 12000.0);\n                double y = log(w);\n                double wt = min(5, c); // cap\n                sw += wt;\n                sy += wt * y;\n            }\n            rowLogMean[i] = (sw > 0.0) ? (sy / sw) : log(5000.0);\n        }\n        for (int j = 0; j < N; j++) {\n            double sw = 0.0, sy = 0.0;\n            for (int i = 0; i < VH; i++) {\n                int c = vc[i][j];\n                if (c <= 0) continue;\n                double w = clampd(v[i][j], 500.0, 12000.0);\n                double y = log(w);\n                double wt = min(5, c);\n                sw += wt;\n                sy += wt * y;\n            }\n            colLogMean[j] = (sw > 0.0) ? (sy / sw) : log(5000.0);\n        }\n    }\n\n    // planning base weight: blend low-count edges toward row/col mean (planning only)\n    inline double planBaseWeight(const EdgeRef &e) const {\n        double w = rawEdgeWeight(e);\n        int cnt = cval(e);\n\n        // Only for very low-count edges\n        constexpr int TH = 2; // counts 0 or 1\n        if (cnt >= TH) return w;\n\n        double y = log(w);\n        double prior = e.horiz ? rowLogMean[e.i] : colLogMean[e.j];\n\n        // stronger when cnt=0, weaker when cnt=1\n        double lam = 0.60 * (double)(TH - cnt) / TH; // 0.6 or 0.3\n        double by = (1.0 - lam) * y + lam * prior;\n        return clampd(exp(by), 500.0, 12000.0);\n    }\n\n    // planning weight = (blended base) * pessimism / exploration\n    inline double planWeight(const EdgeRef &e, int qk, double explore_scale) const {\n        double base = planBaseWeight(e);\n        int cnt = cval(e);\n\n        double phase = (qk < 280) ? (280.0 - qk) / 280.0 : 0.0; // 1 -> 0\n        double explore = explore_scale * phase;\n        double pess = 0.04 + 0.26 * (1.0 - phase);\n\n        double s = sqrt(cnt + 1.0);\n        double factor = (1.0 + pess / s) / (1.0 + explore / s);\n        return clampd(base * factor, 500.0, 12000.0);\n    }\n\n    vector<int> dijkstraPath(int si, int sj, int ti, int tj, int qk, double explore_scale) const {\n        int s = si * N + sj;\n        int t = ti * N + tj;\n\n        vector<double> dist(N * N, 1e100);\n        vector<int> prev(N * N, -1);\n        using P = pair<double,int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top(); pq.pop();\n            if (d != dist[u]) continue;\n            if (u == t) break;\n\n            int ui = u / N, uj = u % N;\n            auto relax = [&](int w) {\n                EdgeRef e = edgeBetween(u, w);\n                double ww = planWeight(e, qk, explore_scale);\n                double nd = d + ww;\n                if (nd < dist[w]) {\n                    dist[w] = nd;\n                    prev[w] = u;\n                    pq.push({nd, w});\n                }\n            };\n\n            if (uj + 1 < N) relax(u + 1);\n            if (uj - 1 >= 0) relax(u - 1);\n            if (ui + 1 < N) relax(u + N);\n            if (ui - 1 >= 0) relax(u - N);\n        }\n\n        vector<int> nodes;\n        for (int cur = t; cur != -1; cur = prev[cur]) {\n            nodes.push_back(cur);\n            if (cur == s) break;\n        }\n        reverse(nodes.begin(), nodes.end());\n        return nodes;\n    }\n\n    PathInfo buildPathInfo(const vector<int> &nodes) const {\n        PathInfo info;\n        info.nodes = nodes;\n        if (nodes.empty()) return info;\n\n        info.moves.reserve(nodes.size() - 1);\n        info.edges.reserve(nodes.size() - 1);\n        info.base_sum = 0.0;\n\n        for (int idx = 0; idx + 1 < (int)nodes.size(); idx++) {\n            int a = nodes[idx], b = nodes[idx + 1];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            if (bi == ai && bj == aj + 1) info.moves.push_back('R');\n            else if (bi == ai && bj == aj - 1) info.moves.push_back('L');\n            else if (bi == ai + 1 && bj == aj) info.moves.push_back('D');\n            else if (bi == ai - 1 && bj == aj) info.moves.push_back('U');\n            else info.moves.push_back('R');\n\n            EdgeRef e = edgeBetween(a, b);\n            info.edges.push_back(e);\n            info.base_sum += rawEdgeWeight(e); // IMPORTANT: raw weights for learning/prediction consistency\n        }\n        info.base_sum = max(info.base_sum, 1.0);\n        return info;\n    }\n\n    // Same conservative destructive piecewise shrink (only low-count edges), only if enough seen edges.\n    void denoisePiecewise() {\n        auto fit1d = [&](int L,\n                         function<double(int)> getW,\n                         function<int(int)> getC,\n                         function<void(int,double)> setW) {\n            vector<double> y(L), wt(L);\n            vector<int> seen(L, 0), prefSeen(L+1, 0);\n\n            for (int i = 0; i < L; i++) {\n                int c = getC(i);\n                seen[i] = (c > 0);\n                prefSeen[i+1] = prefSeen[i] + seen[i];\n\n                double w = clampd(getW(i), 500.0, 12000.0);\n                y[i] = log(w);\n\n                double cc = (double)c;\n                wt[i] = 0.02 + min(1.0, cc / 4.0);\n            }\n\n            if (prefSeen[L] < 10) return;\n\n            vector<double> prefW(L+1,0), prefWY(L+1,0), prefWY2(L+1,0);\n            for (int i = 0; i < L; i++) {\n                prefW[i+1]   = prefW[i]   + wt[i];\n                prefWY[i+1]  = prefWY[i]  + wt[i]*y[i];\n                prefWY2[i+1] = prefWY2[i] + wt[i]*y[i]*y[i];\n            }\n\n            auto segSSE = [&](int l, int r)->pair<double,double>{\n                double W = prefW[r] - prefW[l];\n                double WY = prefWY[r] - prefWY[l];\n                double WY2 = prefWY2[r] - prefWY2[l];\n                if (W <= 1e-12) return {0.0, log(5000.0)};\n                double m = WY / W;\n                double sse = WY2 - 2*m*WY + m*m*W;\n                return {sse, m};\n            };\n\n            auto [sse1, m1] = segSSE(0, L);\n\n            double bestSSE2 = sse1;\n            int bestX = -1;\n            double bestML = m1, bestMR = m1;\n\n            for (int x = 1; x <= L-1; x++) {\n                int leftSeen = prefSeen[x];\n                int rightSeen = prefSeen[L] - prefSeen[x];\n                if (leftSeen < 4 || rightSeen < 4) continue;\n\n                auto [sseL, mL] = segSSE(0, x);\n                auto [sseR, mR] = segSSE(x, L);\n                double sse2 = sseL + sseR;\n                if (sse2 < bestSSE2) {\n                    bestSSE2 = sse2;\n                    bestX = x;\n                    bestML = mL;\n                    bestMR = mR;\n                }\n            }\n\n            double totalW = prefW[L];\n            bool use2 = false;\n            if (bestX != -1) {\n                double improve = sse1 - bestSSE2;\n                if (improve > 0.010 * totalW) use2 = true;\n            }\n\n            for (int i = 0; i < L; i++) {\n                int c = getC(i);\n                if (c >= 7) continue;\n\n                double target = m1;\n                if (use2) target = (i < bestX) ? bestML : bestMR;\n\n                double scale = (7.0 - c) / 7.0;\n                double lam = (0.10 / sqrt(c + 1.0)) * scale;\n                lam = min(lam, 0.18);\n\n                double ny = (1.0 - lam) * y[i] + lam * target;\n                setW(i, clampd(exp(ny), 500.0, 12000.0));\n            }\n        };\n\n        for (int r = 0; r < N; r++) {\n            fit1d(HW,\n                  [&](int j){ return h[r][j]; },\n                  [&](int j){ return hc[r][j]; },\n                  [&](int j, double val){ h[r][j] = val; });\n        }\n        for (int c = 0; c < N; c++) {\n            fit1d(VH,\n                  [&](int i){ return v[i][c]; },\n                  [&](int i){ return vc[i][c]; },\n                  [&](int i, double val){ v[i][c] = val; });\n        }\n    }\n\n    string query(int si, int sj, int ti, int tj) {\n        updateLineMeans();\n\n        int manhattan = abs(si - ti) + abs(sj - tj);\n        double phase = (k < 280) ? (280.0 - k) / 280.0 : 0.0;\n        double margin = 0.025 + 0.085 * phase;\n\n        auto exploit_nodes = dijkstraPath(si, sj, ti, tj, k, 0.0);\n        auto exploit = buildPathInfo(exploit_nodes);\n\n        auto explore_nodes = dijkstraPath(si, sj, ti, tj, k, 0.55);\n        auto explore = buildPathInfo(explore_nodes);\n\n        bool explore_ok = true;\n        if ((int)explore.nodes.size() - 1 > manhattan + 75) explore_ok = false;\n\n        const PathInfo *chosen = &exploit;\n        if (explore_ok && explore.base_sum <= exploit.base_sum * (1.0 + margin)) {\n            chosen = &explore;\n        }\n\n        last_edges = chosen->edges;\n        last_pred = chosen->base_sum;\n        return chosen->moves;\n    }\n\n    void feedback(long long observed) {\n        if (last_edges.empty()) { k++; return; }\n\n        double lo, hi;\n        if (k < 40) { lo = 0.70; hi = 1.40; }\n        else if (k < 180) {\n            double a = (k - 40) / 140.0;\n            lo = 0.70 + a * (0.85 - 0.70);\n            hi = 1.40 + a * (1.18 - 1.40);\n        } else {\n            lo = 0.85; hi = 1.18;\n        }\n\n        double ratio = (double)observed / last_pred;\n        ratio = clampd(ratio, lo, hi);\n        double logratio = log(ratio);\n\n        double t = (double)k / 1000.0;\n        double base_lr = 0.85 * (1.0 - t) + 0.25;\n\n        double denom = 0.0;\n        for (auto &e : last_edges) {\n            double w = rawEdgeWeight(e);\n            double share = w / last_pred;\n            double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n            denom += share * share * damp;\n        }\n        denom = max(denom, 1e-12);\n        double alpha = base_lr / denom;\n\n        for (auto &e : last_edges) {\n            double w = rawEdgeWeight(e);\n            double share = w / last_pred;\n            double damp = 1.0 / sqrt((double)cval(e) + 1.0);\n\n            double dx = alpha * logratio * share * damp;\n            dx = clampd(dx, -0.28, 0.28);\n\n            double &ww = wref(e);\n            ww *= exp(dx);\n            ww = clampd(ww, 500.0, 12000.0);\n\n            cref(e)++;\n        }\n\n        if (k >= 80 && (k % 26 == 25)) denoisePiecewise();\n\n        k++;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    for (int q = 0; q < 1000; q++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        string path = solver.query(si, sj, ti, tj);\n        cout << path << \"\\n\" << flush;\n\n        long long res;\n        cin >> res;\n        solver.feedback(res);\n    }\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr uint8_t DOT = 8; // only used in dot pruning\n\n// ---------- RNG (splitmix64) ----------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Hasher {\n    size_t operator()(uint64_t x) const noexcept {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        x ^= (x >> 31);\n        return (size_t)x;\n    }\n};\n\nusing FlatMap = boost::unordered_flat_map<uint64_t, int, Hasher>;\n\n// code = (len<<36) | bits (3 bits per char)\nstatic inline uint64_t encodeVec(const vector<uint8_t>& v, int st, int len) {\n    uint64_t bits = 0;\n    for (int i = 0; i < len; i++) bits = (bits << 3) | (uint64_t)v[st + i];\n    return (uint64_t(len) << 36) | bits;\n}\nstatic inline uint64_t encodeFull(const vector<uint8_t>& v) {\n    return encodeVec(v, 0, (int)v.size());\n}\nstatic inline uint64_t bitsMask(int len) {\n    return (len == 0) ? 0ULL : ((1ULL << (3 * len)) - 1ULL);\n}\nstatic inline vector<uint8_t> decodeCode(uint64_t code) {\n    int len = int(code >> 36);\n    vector<uint8_t> v(len);\n    uint64_t bits = code & bitsMask(len);\n    for (int i = len - 1; i >= 0; i--) {\n        v[i] = uint8_t(bits & 7ULL);\n        bits >>= 3;\n    }\n    return v;\n}\n\nstruct CodeBook {\n    int minLen = 2, maxLen = 12;\n    // mapByLen[len][bits] -> idx\n    vector<FlatMap> mapByLen;\n    vector<int> weight;                // multiplicity per idx\n    vector<vector<uint8_t>> pattern;   // only for full objective\n    vector<int> impPriority;           // only for full objective\n    long long totalWeight = 0;\n};\n\nstatic CodeBook makeCodeBook(const FlatMap& wmap, int minLen, int maxLen, bool storePattern) {\n    CodeBook book;\n    book.minLen = minLen;\n    book.maxLen = maxLen;\n    book.mapByLen.resize(maxLen + 1);\n\n    vector<int> cnt(maxLen + 1, 0);\n    for (auto &kv : wmap) {\n        int len = int(kv.first >> 36);\n        if (len >= minLen && len <= maxLen) cnt[len]++;\n    }\n    for (int len = minLen; len <= maxLen; len++) {\n        if (cnt[len] > 0) {\n            book.mapByLen[len].reserve((size_t)cnt[len] * 2 + 8);\n            book.mapByLen[len].max_load_factor(0.70f);\n        }\n    }\n\n    book.weight.reserve(wmap.size());\n    if (storePattern) {\n        book.pattern.reserve(wmap.size());\n        book.impPriority.reserve(wmap.size());\n    }\n\n    int idx = 0;\n    long long sum = 0;\n    for (auto &kv : wmap) {\n        uint64_t code = kv.first;\n        int len = int(code >> 36);\n        if (len < minLen || len > maxLen) continue;\n\n        uint64_t bits = code & bitsMask(len);\n        int w = kv.second;\n\n        book.mapByLen[len].emplace(bits, idx);\n        book.weight.push_back(w);\n        sum += w;\n\n        if (storePattern) {\n            auto pat = decodeCode(code);\n            int L = (int)pat.size();\n            long long p = 1LL * L * L * L * w; // long & frequent first\n            if (p > INT_MAX) p = INT_MAX;\n            book.pattern.push_back(std::move(pat));\n            book.impPriority.push_back((int)p);\n        }\n        idx++;\n    }\n    book.totalWeight = sum;\n    return book;\n}\n\n// ---------- incremental state ----------\nstruct SAState {\n    array<array<uint8_t, N>, N>* mat = nullptr;\n    const CodeBook* book = nullptr;\n\n    vector<int> occ;\n    long long score = 0;\n    array<vector<int>, 40> lineIdx;\n\n    vector<int> tmpA, tmpB;\n\n    SAState() {\n        tmpA.reserve(256);\n        tmpB.reserve(256);\n        for (auto &v : lineIdx) v.reserve(256);\n    }\n\n    inline void getLineSeq(int lineId, uint8_t seq[N]) const {\n        if (lineId < 20) {\n            int r = lineId;\n            for (int c = 0; c < N; c++) seq[c] = (*mat)[r][c];\n        } else {\n            int c = lineId - 20;\n            for (int r = 0; r < N; r++) seq[r] = (*mat)[r][c];\n        }\n    }\n\n    inline void computeLineInto(int lineId, vector<int>& out) const {\n        out.clear();\n        uint8_t seq[N];\n        getLineSeq(lineId, seq);\n\n        const int minL = book->minLen;\n        const int maxL = book->maxLen;\n\n        for (int st = 0; st < N; st++) {\n            uint64_t bits = 0;\n            int pos = st;\n            for (int l = 1; l <= maxL; l++) {\n                uint8_t v = seq[pos];\n                if (v == DOT) break;\n                bits = (bits << 3) | (uint64_t)v;\n                if (l >= minL) {\n                    auto &mp = book->mapByLen[l];\n                    if (!mp.empty()) {\n                        auto it = mp.find(bits);\n                        if (it != mp.end()) out.push_back(it->second);\n                    }\n                }\n                pos++;\n                if (pos == N) pos = 0;\n            }\n        }\n    }\n\n    inline void replaceSwapLine(int lineId, vector<int>& newVec) {\n        for (int idx : lineIdx[lineId]) {\n            int &x = occ[idx];\n            x--;\n            if (x == 0) score -= book->weight[idx];\n        }\n        for (int idx : newVec) {\n            int &x = occ[idx];\n            if (x == 0) score += book->weight[idx];\n            x++;\n        }\n        lineIdx[lineId].swap(newVec);\n    }\n\n    void init(array<array<uint8_t, N>, N> &m, const CodeBook& b) {\n        mat = &m;\n        book = &b;\n        occ.assign(book->weight.size(), 0);\n        score = 0;\n        for (int lineId = 0; lineId < 40; lineId++) {\n            vector<int> tmp;\n            tmp.reserve(256);\n            computeLineInto(lineId, tmp);\n            lineIdx[lineId] = std::move(tmp);\n            for (int idx : lineIdx[lineId]) {\n                int &x = occ[idx];\n                if (x == 0) score += book->weight[idx];\n                x++;\n            }\n        }\n        tmpA.clear(); tmpB.clear();\n        tmpA.reserve(256); tmpB.reserve(256);\n    }\n};\n\nstruct Solver {\n    int M;\n    vector<vector<uint8_t>> inputs;\n    RNG rng;\n    array<array<uint8_t, N>, N> mat;\n    chrono::steady_clock::time_point startTime;\n\n    explicit Solver(int M) : M(M) {\n        uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n        rng = RNG(seed);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    inline double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void initByFreq() {\n        array<long long, 8> freq{};\n        long long tot = 0;\n        for (auto &s : inputs) for (uint8_t v : s) { freq[v]++; tot++; }\n        if (tot == 0) return;\n\n        array<double, 8> acc{};\n        double sum = 0;\n        for (int i = 0; i < 8; i++) sum += (double)freq[i] + 1.0;\n        double cur = 0;\n        for (int i = 0; i < 8; i++) { cur += ((double)freq[i] + 1.0) / sum; acc[i] = cur; }\n\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            double r = rng.nextDouble();\n            int v = 0;\n            while (v < 7 && r > acc[v]) v++;\n            mat[i][j] = (uint8_t)v;\n        }\n        for (int t = 0; t < 10; t++) mat[rng.nextInt(0, N - 1)][rng.nextInt(0, N - 1)] = (uint8_t)rng.nextInt(0, 7);\n    }\n\n    struct CellCh { int r, c; uint8_t oldv; };\n\n    bool tryApplyCells(SAState& st, const vector<CellCh>& changes, double T) {\n        if (changes.empty()) return false;\n\n        bool mark[40] = {};\n        int lids[40], lidCount = 0;\n        auto addLine = [&](int id) { if (!mark[id]) { mark[id] = true; lids[lidCount++] = id; } };\n        for (auto &ch : changes) { addLine(ch.r); addLine(20 + ch.c); }\n\n        long long oldScore = st.score;\n\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n        vector<int> tmp; tmp.reserve(256);\n\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            tmp.clear();\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp); // tmp becomes old\n            backups.emplace_back(lid, vector<int>());\n            backups.back().second.swap(tmp);\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            for (int k = (int)backups.size() - 1; k >= 0; k--) st.replaceSwapLine(backups[k].first, backups[k].second);\n            for (auto &ch : changes) mat[ch.r][ch.c] = ch.oldv;\n        }\n        return accept;\n    }\n\n    bool tryRotate(SAState& st, bool rotateRow, int id, int shift, double T) {\n        shift %= N;\n        if (shift < 0) shift += N;\n        if (shift == 0) return false;\n\n        array<uint8_t, N> buf{};\n        if (rotateRow) {\n            for (int c = 0; c < N; c++) buf[c] = mat[id][c];\n            for (int c = 0; c < N; c++) mat[id][(c + shift) % N] = buf[c];\n        } else {\n            for (int r = 0; r < N; r++) buf[r] = mat[r][id];\n            for (int r = 0; r < N; r++) mat[(r + shift) % N][id] = buf[r];\n        }\n\n        int lids[21], lidCount = 0;\n        if (rotateRow) {\n            lids[lidCount++] = id;\n            for (int c = 0; c < N; c++) lids[lidCount++] = 20 + c;\n        } else {\n            lids[lidCount++] = 20 + id;\n            for (int r = 0; r < N; r++) lids[lidCount++] = r;\n        }\n\n        long long oldScore = st.score;\n\n        vector<pair<int, vector<int>>> backups;\n        backups.reserve(lidCount);\n        vector<int> tmp; tmp.reserve(256);\n\n        for (int k = 0; k < lidCount; k++) {\n            int lid = lids[k];\n            tmp.clear();\n            st.computeLineInto(lid, tmp);\n            st.replaceSwapLine(lid, tmp);\n            backups.emplace_back(lid, vector<int>());\n            backups.back().second.swap(tmp);\n        }\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double u = max(1e-300, rng.nextDouble());\n            if (log(u) < (double)delta / T) accept = true;\n        }\n\n        if (!accept) {\n            for (int k = (int)backups.size() - 1; k >= 0; k--) st.replaceSwapLine(backups[k].first, backups[k].second);\n            if (rotateRow) for (int c = 0; c < N; c++) mat[id][c] = buf[c];\n            else for (int r = 0; r < N; r++) mat[r][id] = buf[r];\n        }\n        return accept;\n    }\n\n    bool doCellMutate(SAState& st, double T) {\n        int i = rng.nextInt(0, N - 1);\n        int j = rng.nextInt(0, N - 1);\n        uint8_t oldv = mat[i][j];\n        uint8_t nv = oldv;\n        while (nv == oldv) nv = (uint8_t)rng.nextInt(0, 7);\n        mat[i][j] = nv;\n        vector<CellCh> changes = {{i, j, oldv}};\n        return tryApplyCells(st, changes, T);\n    }\n\n    // mismatch count for candidate placement of seq[off..off+k) at (line,start,vert)\n    inline int mismatchPlacement(const vector<uint8_t>& seq, int off, int k, bool vert, int line, int start) const {\n        int mism = 0;\n        if (!vert) {\n            int r = line;\n            for (int t = 0; t < k; t++) mism += (mat[r][(start + t) % N] != seq[off + t]);\n        } else {\n            int c = line;\n            for (int t = 0; t < k; t++) mism += (mat[(start + t) % N][c] != seq[off + t]);\n        }\n        return mism;\n    }\n\n    bool doSegmentOverwriteBestPlacement(SAState& st, double T, const vector<uint8_t>& seq, int off, int k, int trials) {\n        bool bestVert = false;\n        int bestLine = 0, bestStart = 0;\n        int bestM = INT_MAX;\n\n        for (int t = 0; t < trials; t++) {\n            bool vert = (rng.nextInt(0, 1) == 1);\n            int line = rng.nextInt(0, N - 1);\n            int start = rng.nextInt(0, N - 1);\n            int m = mismatchPlacement(seq, off, k, vert, line, start);\n            if (m < bestM) {\n                bestM = m;\n                bestVert = vert;\n                bestLine = line;\n                bestStart = start;\n                if (bestM == 0) break;\n            }\n        }\n        if (bestM == 0) return false; // nothing to change\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n\n        if (!bestVert) {\n            int r = bestLine;\n            for (int t = 0; t < k; t++) {\n                int c = (bestStart + t) % N;\n                uint8_t nv = seq[off + t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        } else {\n            int c = bestLine;\n            for (int t = 0; t < k; t++) {\n                int r = (bestStart + t) % N;\n                uint8_t nv = seq[off + t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApplyCells(st, changes, T);\n    }\n\n    bool doSegmentOverwriteFromInput(SAState& st, double T, int minK, int maxK) {\n        int idx = rng.nextInt(0, M - 1);\n        const auto& s = inputs[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n        int k = rng.nextInt(minK, min(maxK, L));\n        int off = rng.nextInt(0, L - k);\n\n        // random placement is cheaper for A/B; still OK for C when not targeting uncovered\n        bool vert = (rng.nextInt(0, 1) == 1);\n        int line = rng.nextInt(0, N - 1);\n        int start = rng.nextInt(0, N - 1);\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n\n        if (!vert) {\n            int r = line;\n            for (int t = 0; t < k; t++) {\n                int c = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        } else {\n            int c = line;\n            for (int t = 0; t < k; t++) {\n                int r = (start + t) % N;\n                uint8_t nv = s[off + t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApplyCells(st, changes, T);\n    }\n\n    int pickUncoveredIdx(const SAState& st, int samples) {\n        int U = (int)st.occ.size();\n        int best = -1, bestP = -1;\n        for (int t = 0; t < samples; t++) {\n            int idx = rng.nextInt(0, U - 1);\n            if (st.occ[idx] != 0) continue;\n            int p = st.book->impPriority.empty() ? 1 : st.book->impPriority[idx];\n            if (p > bestP) { bestP = p; best = idx; }\n        }\n        return best;\n    }\n\n    bool doImposeUncovered(SAState& st, double T) {\n        if (st.book->pattern.empty()) return false;\n        if (st.score >= st.book->totalWeight) return false;\n\n        int target = pickUncoveredIdx(st, 80);\n        if (target < 0) return false;\n\n        const auto& pat = st.book->pattern[target];\n        int k = (int)pat.size();\n        if (k < 2) return false;\n\n        // best mismatch placement\n        bool bestVert = false;\n        int bestLine = 0, bestStart = 0;\n        int bestMismatch = INT_MAX;\n\n        for (int tt = 0; tt < 100; tt++) {\n            bool vert = (rng.nextInt(0, 1) == 1);\n            int line = rng.nextInt(0, N - 1);\n            int start = rng.nextInt(0, N - 1);\n            int mism = mismatchPlacement(pat, 0, k, vert, line, start);\n            if (mism < bestMismatch) {\n                bestMismatch = mism;\n                bestVert = vert;\n                bestLine = line;\n                bestStart = start;\n                if (bestMismatch == 0) break;\n            }\n        }\n        if (bestMismatch == 0) return false;\n\n        vector<CellCh> changes;\n        changes.reserve(k);\n        if (!bestVert) {\n            int r = bestLine;\n            for (int t = 0; t < k; t++) {\n                int c = (bestStart + t) % N;\n                uint8_t nv = pat[t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        } else {\n            int c = bestLine;\n            for (int t = 0; t < k; t++) {\n                int r = (bestStart + t) % N;\n                uint8_t nv = pat[t];\n                if (mat[r][c] != nv) { changes.push_back({r, c, mat[r][c]}); mat[r][c] = nv; }\n            }\n        }\n        if (changes.empty()) return false;\n        return tryApplyCells(st, changes, T);\n    }\n\n    bool doSegmentFromUncoveredBest(SAState& st, double T, int minK, int maxK) {\n        if (st.book->pattern.empty()) return false;\n        int idx = pickUncoveredIdx(st, 80);\n        if (idx < 0) return false;\n        const auto& s = st.book->pattern[idx];\n        int L = (int)s.size();\n        if (L < minK) return false;\n        int k = rng.nextInt(minK, min(maxK, L));\n        int off = rng.nextInt(0, L - k);\n\n        // best-of placements to reduce destructiveness\n        return doSegmentOverwriteBestPlacement(st, T, s, off, k, /*trials*/26);\n    }\n\n    // Anneal window: temperature progress computed on [phaseStart, phaseEnd], loop runs until untilTime.\n    void annealWindow(SAState& st,\n                      double phaseStart, double phaseEnd, double untilTime,\n                      double T0, double T1,\n                      double pImpose, double pRotate, double pSeg,\n                      int segMinK, int segMaxK,\n                      bool allowImpose, bool segFromUncoveredInFull) {\n        while (true) {\n            double now = elapsedSec();\n            if (now >= untilTime) break;\n\n            double prog = (now - phaseStart) / max(1e-9, (phaseEnd - phaseStart));\n            prog = min(1.0, max(0.0, prog));\n            double T = T0 * pow(T1 / T0, prog);\n\n            double pImp = pImpose;\n            if (allowImpose) {\n                double frac = (double)st.score / max(1.0, (double)st.book->totalWeight);\n                pImp = pImpose + (1.0 - frac) * 0.08;\n                if (pImp > 0.30) pImp = 0.30;\n            }\n\n            double r = rng.nextDouble();\n            if (allowImpose && r < pImp) {\n                doImposeUncovered(st, T);\n            } else if (r < pImp + pRotate) {\n                bool row = (rng.nextInt(0, 1) == 0);\n                int id = rng.nextInt(0, N - 1);\n                int sh;\n                // mostly small rotations, sometimes large to escape dead ends\n                if (rng.nextDouble() < 0.85) sh = rng.nextInt(1, 3);\n                else sh = rng.nextInt(1, N - 1);\n                if (rng.nextInt(0, 1)) sh = N - sh;\n                tryRotate(st, row, id, sh, T);\n            } else if (r < pImp + pRotate + pSeg) {\n                if (segFromUncoveredInFull && allowImpose) {\n                    if (!doSegmentFromUncoveredBest(st, T, segMinK, segMaxK)) {\n                        doSegmentOverwriteFromInput(st, T, segMinK, segMaxK);\n                    }\n                } else {\n                    doSegmentOverwriteFromInput(st, T, segMinK, segMaxK);\n                }\n            } else {\n                doCellMutate(st, T);\n            }\n        }\n    }\n\n    void pruneDotsIfAllCovered(const CodeBook& fullBook) {\n        SAState st;\n        st.init(mat, fullBook);\n        if (st.score != fullBook.totalWeight) return;\n\n        vector<int> order(N * N);\n        iota(order.begin(), order.end(), 0);\n        for (int i = (int)order.size() - 1; i > 0; i--) swap(order[i], order[rng.nextInt(0, i)]);\n\n        for (int p : order) {\n            int i = p / N, j = p % N;\n            if (mat[i][j] == DOT) continue;\n\n            uint8_t oldv = mat[i][j];\n            mat[i][j] = DOT;\n\n            int rowLine = i, colLine = 20 + j;\n            long long oldScore = st.score;\n\n            st.computeLineInto(rowLine, st.tmpA);\n            st.replaceSwapLine(rowLine, st.tmpA);\n            st.computeLineInto(colLine, st.tmpB);\n            st.replaceSwapLine(colLine, st.tmpB);\n\n            if (st.score != fullBook.totalWeight) {\n                st.replaceSwapLine(colLine, st.tmpB);\n                st.replaceSwapLine(rowLine, st.tmpA);\n                mat[i][j] = oldv;\n                st.score = oldScore;\n            }\n        }\n    }\n\n    void solveAndPrint() {\n        // Build books: A (k-mers), B (k-mers + boosted full), C (full only)\n        FlatMap wA; wA.reserve((size_t)25000);\n        FlatMap wB; wB.reserve((size_t)35000);\n        FlatMap wC; wC.reserve((size_t)2048);\n\n        auto addSubs = [&](FlatMap& w, const vector<uint8_t>& s, int minLen, int maxLen, int base) {\n            int L = (int)s.size();\n            for (int len = minLen; len <= maxLen; len++) {\n                if (len > L) break;\n                int mul = base * (len * len);\n                for (int st = 0; st + len <= L; st++) w[encodeVec(s, st, len)] += mul;\n            }\n        };\n\n        const int FULL_BOOST = 80;\n        for (auto &s : inputs) {\n            wC[encodeFull(s)] += 1;\n            wB[encodeFull(s)] += FULL_BOOST;\n            addSubs(wA, s, 3, 7, 1);\n            addSubs(wB, s, 4, 8, 1);\n        }\n\n        CodeBook bookA = makeCodeBook(wA, 3, 7, false);\n        CodeBook bookB = makeCodeBook(wB, 2, 12, false);\n        CodeBook bookC = makeCodeBook(wC, 2, 12, true);\n\n        startTime = chrono::steady_clock::now();\n        const double TL = 2.88;\n\n        initByFreq();\n        SAState st;\n\n        // time split tuned for stability\n        const double phaseAEnd = 0.80;\n        const double phaseBEnd = 2.20;\n        const double phaseCEnd = TL - 0.06;\n        const double fullSAEnd = phaseCEnd - 0.11;\n\n        // Phase A\n        st.init(mat, bookA);\n        annealWindow(st, 0.0, phaseAEnd, min(phaseAEnd, TL),\n                     4500.0, 40.0,\n                     0.0, 0.015, 0.14,\n                     4, 9,\n                     false, false);\n\n        // Phase B\n        st.init(mat, bookB);\n        annealWindow(st, phaseAEnd, phaseBEnd, min(phaseBEnd, TL),\n                     3000.0, 15.0,\n                     0.0, 0.020, 0.18,\n                     5, 12,\n                     false, false);\n\n        // Phase C with snapshot + gentle rollback\n        st.init(mat, bookC);\n        array<array<uint8_t, N>, N> bestMat = mat;\n        long long bestScore = st.score;\n\n        int stagnant = 0;\n        const long long rollbackThresh = 30; // less aggressive than before\n\n        while (elapsedSec() < fullSAEnd) {\n            double segUntil = min(fullSAEnd, elapsedSec() + 0.22);\n\n            annealWindow(st, phaseBEnd, phaseCEnd, segUntil,\n                         210.0, 0.8,\n                         0.16, 0.020, 0.10,\n                         6, 12,\n                         true, true);\n\n            if (st.score > bestScore) {\n                bestScore = st.score;\n                bestMat = mat;\n                stagnant = 0;\n            } else {\n                stagnant++;\n                if (stagnant >= 3 && bestScore - st.score >= rollbackThresh) {\n                    mat = bestMat;\n                    st.init(mat, bookC);\n                    stagnant = 0;\n                }\n            }\n        }\n\n        // finalize from best\n        mat = bestMat;\n        st.init(mat, bookC);\n\n        // Greedy finishing: keep trying within time\n        while (elapsedSec() < phaseCEnd - 0.02 && st.score < bookC.totalWeight) {\n            if (rng.nextDouble() < 0.60) doImposeUncovered(st, 1e-9);\n            else doSegmentFromUncoveredBest(st, 1e-9, 6, 12);\n        }\n\n        pruneDotsIfAllCovered(bookC);\n\n        for (int i = 0; i < N; i++) {\n            string out;\n            out.reserve(N);\n            for (int j = 0; j < N; j++) {\n                uint8_t v = mat[i][j];\n                out.push_back(v == DOT ? '.' : char('A' + v));\n            }\n            cout << out << \"\\n\";\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, M;\n    cin >> n >> M;\n\n    Solver solver(M);\n    solver.inputs.reserve(M);\n    for (int i = 0; i < M; i++) {\n        string s;\n        cin >> s;\n        vector<uint8_t> v;\n        v.reserve(s.size());\n        for (char c : s) v.push_back((uint8_t)(c - 'A')); // A..H -> 0..7\n        solver.inputs.push_back(std::move(v));\n    }\n\n    solver.solveAndPrint();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed=88172645463325252ULL) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    uint64_t operator()() { return next(); }\n    int next_int(int lo, int hi) { return lo + (int)(next() % (uint64_t)(hi - lo + 1)); }\n    double next_double() { return (next() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct TimeKeeper {\n    chrono::steady_clock::time_point st;\n    double limit;\n    TimeKeeper(double limitSec): st(chrono::steady_clock::now()), limit(limitSec) {}\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n    double remaining() const { return limit - elapsed(); }\n};\n\nstruct HopcroftKarp {\n    int nL, nR;\n    vector<vector<int>> adj;\n    vector<int> dist;\n    vector<int> pairU, pairV;\n\n    HopcroftKarp(int nL=0, int nR=0): nL(nL), nR(nR), adj(nL) {}\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(nL, -1);\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        bool found = false;\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                int u2 = pairV[v];\n                if(u2 != -1 && dist[u2] == -1){\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n                if(u2 == -1) found = true;\n            }\n        }\n        return found;\n    }\n\n    bool dfs(int u) {\n        for(int v: adj[u]){\n            int u2 = pairV[v];\n            if(u2 == -1 || (dist[u2] == dist[u] + 1 && dfs(u2))){\n                pairU[u] = v;\n                pairV[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n    int max_matching() {\n        pairU.assign(nL, -1);\n        pairV.assign(nR, -1);\n        int matching = 0;\n        while(bfs()){\n            for(int u=0; u<nL; u++){\n                if(pairU[u] == -1 && dfs(u)) matching++;\n            }\n        }\n        return matching;\n    }\n\n    pair<vector<char>, vector<char>> min_vertex_cover() {\n        vector<char> visL(nL, 0), visR(nR, 0);\n        queue<int> q;\n        for(int u=0; u<nL; u++){\n            if(pairU[u] == -1){\n                visL[u] = 1;\n                q.push(u);\n            }\n        }\n        while(!q.empty()){\n            int u = q.front(); q.pop();\n            for(int v: adj[u]){\n                if(pairU[u] == v) continue;\n                if(!visR[v]){\n                    visR[v] = 1;\n                    int u2 = pairV[v];\n                    if(u2 != -1 && !visL[u2]){\n                        visL[u2] = 1;\n                        q.push(u2);\n                    }\n                }\n            }\n        }\n        vector<char> coverL(nL, 0), coverR(nR, 0);\n        for(int u=0; u<nL; u++) if(!visL[u]) coverL[u] = 1;\n        for(int v=0; v<nR; v++) if(visR[v])  coverR[v] = 1;\n        return {coverL, coverR};\n    }\n};\n\nstruct Dinic {\n    struct Edge { int to, rev; long long cap; };\n    int N;\n    vector<vector<Edge>> G;\n    vector<int> level, it;\n\n    Dinic(int n=0){ init(n); }\n    void init(int n){\n        N = n;\n        G.assign(N, {});\n        level.assign(N, 0);\n        it.assign(N, 0);\n    }\n    void add_edge(int fr, int to, long long cap){\n        Edge a{to, (int)G[to].size(), cap};\n        Edge b{fr, (int)G[fr].size(), 0};\n        G[fr].push_back(a);\n        G[to].push_back(b);\n    }\n    bool bfs(int s, int t){\n        fill(level.begin(), level.end(), -1);\n        queue<int> q;\n        level[s] = 0;\n        q.push(s);\n        while(!q.empty()){\n            int v = q.front(); q.pop();\n            for(const auto &e: G[v]){\n                if(e.cap > 0 && level[e.to] < 0){\n                    level[e.to] = level[v] + 1;\n                    q.push(e.to);\n                }\n            }\n        }\n        return level[t] >= 0;\n    }\n    long long dfs(int v, int t, long long f){\n        if(v == t) return f;\n        for(int &i = it[v]; i < (int)G[v].size(); i++){\n            Edge &e = G[v][i];\n            if(e.cap <= 0 || level[e.to] != level[v] + 1) continue;\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if(ret > 0){\n                e.cap -= ret;\n                G[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n        return 0;\n    }\n    long long max_flow(int s, int t){\n        long long flow = 0;\n        while(bfs(s,t)){\n            fill(it.begin(), it.end(), 0);\n            while(true){\n                long long f = dfs(s,t, (1LL<<62));\n                if(!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n    vector<char> mincut_reachable(int s){\n        vector<char> vis(N, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n        while(!q.empty()){\n            int v = q.front(); q.pop();\n            for(const auto &e: G[v]){\n                if(e.cap > 0 && !vis[e.to]){\n                    vis[e.to] = 1;\n                    q.push(e.to);\n                }\n            }\n        }\n        return vis;\n    }\n};\n\n// Radix heap for uint32 keys\nstruct RadixHeap {\n    using u32 = uint32_t;\n    u32 last = 0;\n    size_t sz = 0;\n    array<vector<pair<u32,int>>, 33> buckets;\n\n    void clear() {\n        for(auto &b: buckets) b.clear();\n        last = 0;\n        sz = 0;\n    }\n    bool empty() const { return sz == 0; }\n\n    static int bindex(u32 x) {\n        if(x == 0) return 0;\n        return 32 - __builtin_clz(x);\n    }\n\n    void push(u32 key, int val) {\n        int idx = (key == last) ? 0 : bindex(key ^ last);\n        buckets[idx].push_back({key, val});\n        sz++;\n    }\n\n    pair<u32,int> pop() {\n        if(buckets[0].empty()){\n            int i = 1;\n            while(i < 33 && buckets[i].empty()) i++;\n            u32 new_last = numeric_limits<u32>::max();\n            for(auto &p: buckets[i]) new_last = min(new_last, p.first);\n            last = new_last;\n            for(auto &p: buckets[i]){\n                u32 key = p.first;\n                int val = p.second;\n                int idx = (key == last) ? 0 : bindex(key ^ last);\n                buckets[idx].push_back({key, val});\n            }\n            buckets[i].clear();\n        }\n        auto res = buckets[0].back();\n        buckets[0].pop_back();\n        sz--;\n        return res;\n    }\n};\n\nstruct Solver {\n    int N, si, sj;\n    vector<string> c;\n\n    vector<vector<int>> id;\n    vector<int> xs, ys, w;\n    int R = 0;\n\n    vector<int> hseg, vseg;\n    int H = 0, V = 0;\n\n    vector<vector<int>> segAdj;\n    vector<int> degH, degV, lenH, lenV;\n\n    vector<array<int,4>> nbr;\n    vector<uint8_t> deg;\n\n    int W64 = 0;\n    vector<uint64_t> visFlat, allMask;\n\n    static constexpr int INF = 1e9;\n    vector<int> dist, prevv;\n    RadixHeap pq;\n\n    void read() {\n        cin >> N >> si >> sj;\n        c.resize(N);\n        for(int i=0;i<N;i++) cin >> c[i];\n    }\n\n    void build_nodes() {\n        id.assign(N, vector<int>(N, -1));\n        xs.clear(); ys.clear(); w.clear();\n        R = 0;\n        for(int i=0;i<N;i++){\n            for(int j=0;j<N;j++){\n                if(c[i][j] == '#') continue;\n                id[i][j] = R++;\n                xs.push_back(i);\n                ys.push_back(j);\n                w.push_back(c[i][j]-'0');\n            }\n        }\n        dist.assign(R, INF);\n        prevv.assign(R, -1);\n        hseg.assign(R, -1);\n        vseg.assign(R, -1);\n\n        nbr.assign(R, array<int,4>{-1,-1,-1,-1});\n        deg.assign(R, 0);\n        for(int v=0; v<R; v++){\n            int x=xs[v], y=ys[v];\n            auto add = [&](int nx,int ny){\n                int u = (0<=nx && nx<N && 0<=ny && ny<N) ? id[nx][ny] : -1;\n                if(u!=-1) nbr[v][deg[v]++] = u;\n            };\n            add(x-1,y); add(x+1,y); add(x,y-1); add(x,y+1);\n        }\n    }\n\n    void build_segments() {\n        H = 0;\n        for(int i=0;i<N;i++){\n            int j=0;\n            while(j<N){\n                if(id[i][j] == -1){ j++; continue; }\n                int sid = H++;\n                while(j<N && id[i][j] != -1){\n                    hseg[id[i][j]] = sid;\n                    j++;\n                }\n            }\n        }\n        V = 0;\n        for(int j=0;j<N;j++){\n            int i=0;\n            while(i<N){\n                if(id[i][j] == -1){ i++; continue; }\n                int sid = V++;\n                while(i<N && id[i][j] != -1){\n                    vseg[id[i][j]] = sid;\n                    i++;\n                }\n            }\n        }\n    }\n\n    void build_segment_graph() {\n        segAdj.assign(H, {});\n        lenH.assign(H, 0);\n        lenV.assign(V, 0);\n        for(int node=0; node<R; node++){\n            segAdj[hseg[node]].push_back(vseg[node]);\n            lenH[hseg[node]]++;\n            lenV[vseg[node]]++;\n        }\n        for(int h=0; h<H; h++){\n            auto &v = segAdj[h];\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n        degH.assign(H, 0);\n        degV.assign(V, 0);\n        for(int h=0; h<H; h++){\n            degH[h] = (int)segAdj[h].size();\n            for(int v: segAdj[h]) degV[v]++;\n        }\n    }\n\n    void build_visibility_bitsets() {\n        W64 = (R + 63) / 64;\n        vector<uint64_t> hbits((size_t)H * W64, 0ULL);\n        vector<uint64_t> vbits((size_t)V * W64, 0ULL);\n        visFlat.assign((size_t)R * W64, 0ULL);\n\n        for(int v=0; v<R; v++){\n            int hi=hseg[v], vi=vseg[v];\n            int word=v>>6, bit=v&63;\n            hbits[(size_t)hi * W64 + word] |= (1ULL<<bit);\n            vbits[(size_t)vi * W64 + word] |= (1ULL<<bit);\n        }\n        for(int v=0; v<R; v++){\n            uint64_t* dst = &visFlat[(size_t)v * W64];\n            const uint64_t* hb = &hbits[(size_t)hseg[v] * W64];\n            const uint64_t* vb = &vbits[(size_t)vseg[v] * W64];\n            for(int k=0;k<W64;k++) dst[k] = hb[k] | vb[k];\n        }\n\n        allMask.assign(W64, ~0ULL);\n        if(R % 64 != 0) allMask[W64-1] = (1ULL << (R%64)) - 1ULL;\n    }\n\n    template<class Pred>\n    int dijkstra_until(int s, Pred pred) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        pq.clear();\n        dist[s] = 0;\n        pq.push(0u, s);\n        while(!pq.empty()){\n            auto [du, v] = pq.pop();\n            int d = (int)du;\n            if(d != dist[v]) continue;\n            if(pred(v)) return v;\n            for(int k=0;k<deg[v];k++){\n                int to = nbr[v][k];\n                int nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push((uint32_t)nd, to);\n                }\n            }\n        }\n        return -1;\n    }\n\n    void dijkstra_store(int s, int* prevOut, int* distOut) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(prevv.begin(), prevv.end(), -1);\n        pq.clear();\n        dist[s] = 0;\n        pq.push(0u, s);\n        while(!pq.empty()){\n            auto [du, v] = pq.pop();\n            int d = (int)du;\n            if(d != dist[v]) continue;\n            for(int k=0;k<deg[v];k++){\n                int to = nbr[v][k];\n                int nd = d + w[to];\n                if(nd < dist[to]){\n                    dist[to] = nd;\n                    prevv[to] = v;\n                    pq.push((uint32_t)nd, to);\n                }\n            }\n        }\n        memcpy(prevOut, prevv.data(), sizeof(int)*R);\n        memcpy(distOut, dist.data(), sizeof(int)*R);\n    }\n\n    pair<vector<char>, vector<char>> compute_min_vertex_cover_card(bool shuffleAdj, XorShift64& rng) {\n        HopcroftKarp hk(H, V);\n        hk.adj = segAdj;\n        if(shuffleAdj){\n            for(int h=0; h<H; h++){\n                auto &v = hk.adj[h];\n                for(int i=(int)v.size()-1;i>0;i--){\n                    int j = (int)(rng() % (uint64_t)(i+1));\n                    swap(v[i], v[j]);\n                }\n            }\n        }\n        hk.max_matching();\n        return hk.min_vertex_cover();\n    }\n\n    pair<vector<char>, vector<char>> compute_min_vertex_cover_weighted(const vector<long long>& wH,\n                                                                       const vector<long long>& wV) {\n        const long long INF_CAP = (1LL<<50);\n        int S = H + V;\n        int T = H + V + 1;\n        Dinic din(H + V + 2);\n        for(int h=0; h<H; h++) din.add_edge(S, h, wH[h]);\n        for(int v=0; v<V; v++) din.add_edge(H + v, T, wV[v]);\n        for(int h=0; h<H; h++) for(int v: segAdj[h]) din.add_edge(h, H+v, INF_CAP);\n        din.max_flow(S, T);\n        auto reach = din.mincut_reachable(S);\n        vector<char> coverH(H, 0), coverV(V, 0);\n        for(int h=0; h<H; h++) if(!reach[h]) coverH[h] = 1;\n        for(int v=0; v<V; v++) if(reach[H+v]) coverV[v] = 1;\n        return {coverH, coverV};\n    }\n\n    struct Top3 {\n        array<int,3> d;\n        array<int,3> v;\n        Top3(){ d = {INF,INF,INF}; v = {-1,-1,-1}; }\n        void upd(int nd, int nv){\n            for(int k=0;k<3;k++){\n                if(nd < d[k]){\n                    for(int t=2;t>k;t--){ d[t]=d[t-1]; v[t]=v[t-1]; }\n                    d[k]=nd; v[k]=nv;\n                    return;\n                }\n            }\n        }\n        int pick(bool randomPick, XorShift64& rng) const {\n            if(!randomPick) return v[0];\n            int cand[3]; int m=0;\n            for(int k=0;k<3;k++) if(v[k]!=-1) cand[m++] = v[k];\n            if(m==0) return -1;\n            return cand[rng.next_int(0, m-1)];\n        }\n    };\n\n    vector<int> build_waypoints_unpaired(const vector<char>& needH, const vector<char>& needV,\n                                         int startId, const vector<int>& distS,\n                                         bool randomPick, XorShift64& rng) {\n        vector<Top3> bestH(H), bestV(V);\n        for(int node=0; node<R; node++){\n            int h=hseg[node], v=vseg[node];\n            if(needH[h]) bestH[h].upd(distS[node], node);\n            if(needV[v]) bestV[v].upd(distS[node], node);\n        }\n        vector<int> wp;\n        wp.push_back(startId);\n        vector<int> tail;\n        tail.reserve(H+V);\n        for(int h=0; h<H; h++) if(needH[h]) {\n            int node = bestH[h].pick(randomPick, rng);\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n        for(int v=0; v<V; v++) if(needV[v]) {\n            int node = bestV[v].pick(randomPick, rng);\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n        sort(tail.begin(), tail.end());\n        tail.erase(unique(tail.begin(), tail.end()), tail.end());\n        wp.insert(wp.end(), tail.begin(), tail.end());\n        if(wp.size()==1 && R>1 && deg[startId]) wp.push_back(nbr[startId][0]);\n        return wp;\n    }\n\n    vector<int> build_waypoints_paired(const vector<char>& needH, const vector<char>& needV,\n                                       int startId, const vector<int>& distS,\n                                       bool randomPick, XorShift64& rng) {\n        vector<int> mapH(H,-1), mapV(V,-1), reqH, reqV;\n        for(int h=0; h<H; h++) if(needH[h]) { mapH[h]=(int)reqH.size(); reqH.push_back(h); }\n        for(int v=0; v<V; v++) if(needV[v]) { mapV[v]=(int)reqV.size(); reqV.push_back(v); }\n        int Hr=(int)reqH.size(), Vr=(int)reqV.size();\n\n        vector<Top3> bestH(Hr), bestV(Vr);\n\n        struct Rep2 { int d1=INF, n1=-1, d2=INF, n2=-1; };\n        unordered_map<uint64_t, Rep2> rep;\n        rep.reserve((size_t)R * 2);\n\n        auto keyUV = [&](int u, int v)->uint64_t {\n            return (uint64_t)(uint32_t)u<<32 | (uint32_t)v;\n        };\n\n        for(int node=0; node<R; node++){\n            int h=hseg[node], v=vseg[node];\n            int u = mapH[h], vv = mapV[v];\n            if(u!=-1) bestH[u].upd(distS[node], node);\n            if(vv!=-1) bestV[vv].upd(distS[node], node);\n\n            if(u!=-1 && vv!=-1){\n                uint64_t key = keyUV(u,vv);\n                auto &r = rep[key];\n                int d = distS[node];\n                if(d < r.d1){\n                    r.d2=r.d1; r.n2=r.n1;\n                    r.d1=d; r.n1=node;\n                }else if(d < r.d2 && node != r.n1){\n                    r.d2=d; r.n2=node;\n                }\n            }\n        }\n\n        HopcroftKarp hk(Hr, Vr);\n        hk.adj.assign(Hr, {});\n        for(auto &kv : rep){\n            uint64_t key = kv.first;\n            int u = (int)(key >> 32);\n            int vv = (int)(key & 0xffffffffu);\n            hk.adj[u].push_back(vv);\n        }\n        for(int u=0; u<Hr; u++){\n            auto &vec = hk.adj[u];\n            sort(vec.begin(), vec.end());\n            vec.erase(unique(vec.begin(), vec.end()), vec.end());\n            if(randomPick && vec.size() >= 2){\n                for(int i=(int)vec.size()-1;i>0;i--){\n                    int j = (int)(rng() % (uint64_t)(i+1));\n                    swap(vec[i], vec[j]);\n                }\n            }\n        }\n\n        hk.max_matching();\n        vector<char> matchedV(Vr, 0);\n\n        vector<int> wp; wp.push_back(startId);\n        vector<int> tail;\n        tail.reserve(Hr+Vr);\n\n        for(int u=0; u<Hr; u++){\n            int vv = hk.pairU[u];\n            if(vv!=-1){\n                matchedV[vv]=1;\n                auto &r = rep[keyUV(u,vv)];\n                int node = r.n1;\n                if(randomPick && r.n2!=-1 && (rng() & 1ULL)) node = r.n2;\n                if(node!=-1 && node!=startId) tail.push_back(node);\n            }else{\n                int node = bestH[u].v[0];\n                if(node!=-1 && node!=startId) tail.push_back(node);\n            }\n        }\n        for(int vv=0; vv<Vr; vv++){\n            if(matchedV[vv]) continue;\n            int node = bestV[vv].v[0];\n            if(node!=-1 && node!=startId) tail.push_back(node);\n        }\n\n        sort(tail.begin(), tail.end());\n        tail.erase(unique(tail.begin(), tail.end()), tail.end());\n        wp.insert(wp.end(), tail.begin(), tail.end());\n        if(wp.size()==1 && R>1 && deg[startId]) wp.push_back(nbr[startId][0]);\n        return wp;\n    }\n\n    void build_apsp_with_prevs(const vector<int>& wp, vector<int>& Dflat, vector<int>& prevs, vector<int>& distRowBuf) {\n        int m = (int)wp.size();\n        Dflat.assign(m*m, INF);\n        prevs.assign((size_t)m * R, -1);\n        distRowBuf.resize(R);\n        for(int i=0;i<m;i++){\n            dijkstra_store(wp[i], &prevs[(size_t)i * R], distRowBuf.data());\n            for(int j=0;j<m;j++){\n                Dflat[i*m + j] = distRowBuf[wp[j]];\n            }\n        }\n    }\n\n    inline long long cycle_cost(const vector<int>& seq, const vector<int>& Dflat, int m) const {\n        long long cost=0;\n        for(int i=0;i<m;i++) cost += Dflat[seq[i]*m + seq[(i+1)%m]];\n        return cost;\n    }\n\n    vector<int> init_nearest_neighbor(const vector<int>& Dflat, int m) {\n        vector<int> seq; seq.reserve(m);\n        vector<char> used(m, 0);\n        int cur = 0;\n        seq.push_back(0); used[0]=1;\n        for(int step=1; step<m; step++){\n            int best=-1, bestD=INF;\n            for(int j=1;j<m;j++){\n                if(used[j]) continue;\n                int d = Dflat[cur*m + j];\n                if(d < bestD){ bestD=d; best=j; }\n            }\n            if(best==-1){\n                for(int j=1;j<m;j++) if(!used[j]) { best=j; break; }\n            }\n            used[best]=1;\n            seq.push_back(best);\n            cur = best;\n        }\n        return seq;\n    }\n\n    vector<int> init_cheapest_insertion(const vector<int>& Dflat, int m) {\n        if(m <= 2){\n            vector<int> seq(m);\n            iota(seq.begin(), seq.end(), 0);\n            return seq;\n        }\n        vector<char> used(m, 0);\n        used[0] = 1;\n\n        int best2 = 1;\n        long long bestVal = (long long)Dflat[0*m + 1] + Dflat[1*m + 0];\n        for(int j=2;j<m;j++){\n            long long v = (long long)Dflat[0*m + j] + Dflat[j*m + 0];\n            if(v < bestVal){\n                bestVal = v;\n                best2 = j;\n            }\n        }\n        vector<int> seq = {0, best2};\n        used[best2] = 1;\n\n        for(int cnt=2; cnt<m; cnt++){\n            int bestX=-1, bestPos=-1;\n            long long bestDelta = (1LL<<60);\n            for(int x=1;x<m;x++){\n                if(used[x]) continue;\n                int L = (int)seq.size();\n                for(int pos=0; pos<L; pos++){\n                    int a = seq[pos];\n                    int b = seq[(pos+1)%L];\n                    long long delta = (long long)Dflat[a*m + x] + Dflat[x*m + b] - Dflat[a*m + b];\n                    if(delta < bestDelta){\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n            seq.insert(seq.begin() + bestPos + 1, bestX);\n            used[bestX] = 1;\n        }\n        auto it = find(seq.begin(), seq.end(), 0);\n        rotate(seq.begin(), it, seq.end());\n        return seq;\n    }\n\n    void optimize_waypoint_order_sa(vector<int>& seq, const vector<int>& Dflat, int m, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        if(m <= 3) return;\n\n        auto prev_idx = [&](int i){ return (i-1+m)%m; };\n        auto next_idx = [&](int i){ return (i+1)%m; };\n\n        long long curCost = cycle_cost(seq, Dflat, m);\n        vector<int> bestSeq = seq;\n        long long bestCost = curCost;\n\n        const double T0 = 4500.0;\n        const double T1 = 8.0;\n\n        int iter = 0;\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n            double frac = elapsed / max(1e-9, timeLimitSec);\n            double temp = T0 * pow(T1 / T0, frac);\n\n            int op = (int)(rng() % 3);\n            if(op == 0){\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = (int)(rng() % (uint64_t)m);\n                if(j==i) continue;\n                if(next_idx(j)==i) continue;\n\n                int pi=prev_idx(i), ni=next_idx(i);\n                int a=seq[pi], x=seq[i], b=seq[ni];\n                int c=seq[j], d=seq[next_idx(j)];\n\n                long long old = (long long)Dflat[a*m + x] + Dflat[x*m + b] + Dflat[c*m + d];\n                long long neu = (long long)Dflat[a*m + b] + Dflat[c*m + x] + Dflat[x*m + d];\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    int xval = seq[i];\n                    if(i < j){\n                        seq.erase(seq.begin()+i);\n                        seq.insert(seq.begin()+j, xval);\n                    }else{\n                        seq.erase(seq.begin()+i);\n                        seq.insert(seq.begin()+j+1, xval);\n                    }\n                    if(seq[0] != 0){\n                        auto it = find(seq.begin(), seq.end(), 0);\n                        rotate(seq.begin(), it, seq.end());\n                    }\n                    curCost += delta;\n                }\n            }else if(op == 1){\n                int i = 1 + (int)(rng() % (uint64_t)(m-1));\n                int j = 1 + (int)(rng() % (uint64_t)(m-1));\n                if(i==j) continue;\n                if(i>j) swap(i,j);\n\n                int pi=prev_idx(i), ni=next_idx(i);\n                int pj=prev_idx(j), nj=next_idx(j);\n\n                int a=seq[pi], b=seq[i], c=seq[ni];\n                int d=seq[pj], e=seq[j], f=seq[nj];\n\n                long long old, neu;\n                if(ni == j){\n                    old = (long long)Dflat[a*m + b] + Dflat[b*m + e] + Dflat[e*m + f];\n                    neu = (long long)Dflat[a*m + e] + Dflat[e*m + b] + Dflat[b*m + f];\n                }else{\n                    old = (long long)Dflat[a*m + b] + Dflat[b*m + c] + Dflat[d*m + e] + Dflat[e*m + f];\n                    neu = (long long)Dflat[a*m + e] + Dflat[e*m + c] + Dflat[d*m + b] + Dflat[b*m + f];\n                }\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                }\n            }else{\n                if(m < 5) continue;\n                int i = 1 + (int)(rng() % (uint64_t)(m-2));\n                int i2 = i + 1;\n                int j = (int)(rng() % (uint64_t)m);\n                if(j==i || j==i2) continue;\n\n                int pi = i-1;\n                int ni = (i2+1)%m;\n                int jn = (j+1)%m;\n                if(j == pi) continue;\n                if(jn == i || jn == i2) continue;\n\n                int P = seq[pi];\n                int A = seq[i];\n                int B = seq[i2];\n                int Nn = seq[ni];\n                int J = seq[j];\n                int JN = seq[jn];\n\n                long long old = (long long)Dflat[P*m + A] + Dflat[B*m + Nn] + Dflat[J*m + JN];\n                long long neu = (long long)Dflat[P*m + Nn] + Dflat[J*m + A] + Dflat[B*m + JN];\n                long long delta = neu - old;\n\n                if(delta < 0 || rng.next_double() < exp(-(double)delta / temp)){\n                    int Aval=A, Bval=B;\n                    seq.erase(seq.begin()+i2);\n                    seq.erase(seq.begin()+i);\n                    int jj = j;\n                    if(j > i2) jj -= 2;\n                    int pos = jj + 1;\n                    if(pos > (int)seq.size()) pos = (int)seq.size();\n                    seq.insert(seq.begin()+pos, Aval);\n                    seq.insert(seq.begin()+pos+1, Bval);\n                    if(seq[0] != 0){\n                        auto it = find(seq.begin(), seq.end(), 0);\n                        rotate(seq.begin(), it, seq.end());\n                    }\n                    curCost += delta;\n                }\n            }\n\n            if((++iter & 127) == 0){\n                curCost = cycle_cost(seq, Dflat, m);\n            }\n            if(curCost < bestCost){\n                bestCost = curCost;\n                bestSeq = seq;\n            }\n        }\n        seq.swap(bestSeq);\n    }\n\n    vector<int> expand_route_from_seq(const vector<int>& wp, const vector<int>& seq, const vector<int>& prevs) {\n        int m = (int)wp.size();\n        vector<int> route;\n        route.push_back(wp[seq[0]]);\n        vector<int> tmp; tmp.reserve(512);\n\n        auto restore = [&](int srcIdx, int srcNode, int dstNode){\n            const int* prv = &prevs[(size_t)srcIdx * R];\n            int cur = dstNode;\n            tmp.clear();\n            tmp.push_back(cur);\n            while(cur != srcNode && cur != -1){\n                cur = prv[cur];\n                tmp.push_back(cur);\n            }\n            if(tmp.back() != srcNode) return;\n            reverse(tmp.begin(), tmp.end());\n            for(size_t k=1;k<tmp.size();k++) route.push_back(tmp[k]);\n        };\n\n        for(int i=0;i<m;i++){\n            int a = seq[i];\n            int b = seq[(i+1)%m];\n            restore(a, wp[a], wp[b]);\n        }\n        return route;\n    }\n\n    pair<bool,long long> eval_full_visibility(const vector<int>& route) const {\n        vector<uint64_t> cov(W64, 0ULL);\n        long long t = 0;\n        for(size_t i=0;i<route.size();i++){\n            int v = route[i];\n            if(i) t += w[v];\n            const uint64_t* vb = &visFlat[(size_t)v * W64];\n            for(int k=0;k<W64;k++) cov[k] |= vb[k];\n        }\n        for(int k=0;k<W64;k++){\n            if(cov[k] != allMask[k]) return {false, t};\n        }\n        return {true, t};\n    }\n\n    // Improved shortcut search: bias (a,b) to turning points\n    vector<int> improve_by_shortcuts_full_fast(vector<int> route, double timeLimitSec, XorShift64& rng) {\n        auto st = chrono::steady_clock::now();\n        auto [ok0, bestT] = eval_full_visibility(route);\n        if(!ok0) return route;\n\n        vector<long long> preTime;\n        vector<uint64_t> pref, suf;\n        long long totalT = 0;\n        vector<int> turns;\n\n        auto rebuild_aux = [&](const vector<int>& r){\n            int L=(int)r.size();\n            preTime.assign(L, 0LL);\n            totalT = 0;\n            for(int i=1;i<L;i++){\n                totalT += w[r[i]];\n                preTime[i] = totalT;\n            }\n            pref.assign((size_t)L * W64, 0ULL);\n            suf.assign((size_t)(L+1) * W64, 0ULL);\n\n            for(int i=0;i<L;i++){\n                const uint64_t* vb = &visFlat[(size_t)r[i] * W64];\n                uint64_t* dst = &pref[(size_t)i * W64];\n                if(i==0){\n                    for(int k=0;k<W64;k++) dst[k] = vb[k];\n                }else{\n                    uint64_t* prv = &pref[(size_t)(i-1) * W64];\n                    for(int k=0;k<W64;k++) dst[k] = prv[k] | vb[k];\n                }\n            }\n            for(int i=L-1;i>=0;i--){\n                const uint64_t* vb = &visFlat[(size_t)r[i] * W64];\n                uint64_t* dst = &suf[(size_t)i * W64];\n                uint64_t* nxt = &suf[(size_t)(i+1) * W64];\n                for(int k=0;k<W64;k++) dst[k] = nxt[k] | vb[k];\n            }\n\n            turns.clear();\n            turns.reserve(L/3);\n            for(int i=1;i+1<L;i++){\n                int a=r[i-1], b=r[i], c=r[i+1];\n                int dx1=xs[b]-xs[a], dy1=ys[b]-ys[a];\n                int dx2=xs[c]-xs[b], dy2=ys[c]-ys[b];\n                if(dx1!=dx2 || dy1!=dy2) turns.push_back(i);\n            }\n            // add periodic samples too\n            for(int i=0;i<L;i+=25) turns.push_back(i);\n            sort(turns.begin(), turns.end());\n            turns.erase(unique(turns.begin(), turns.end()), turns.end());\n        };\n\n        rebuild_aux(route);\n\n        while(true){\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n            if(elapsed > timeLimitSec) break;\n\n            int L=(int)route.size();\n            if(L < 12) continue;\n\n            int a=-1, b=-1;\n\n            bool useTurns = (turns.size() >= 2) && ((rng() % 100) < 70);\n            if(useTurns){\n                // pick two turn indices, ensure separation\n                for(int tr=0; tr<6; tr++){\n                    int ia = turns[rng.next_int(0, (int)turns.size()-1)];\n                    int ib = turns[rng.next_int(0, (int)turns.size()-1)];\n                    if(ia==ib) continue;\n                    if(ia>ib) swap(ia,ib);\n                    if(ib - ia < 5) continue;\n                    if(ib >= L) continue;\n                    a = ia;\n                    b = ib;\n                    break;\n                }\n            }\n            if(a==-1){\n                int len = 5 + (int)(rng() % 260);\n                if(len >= L) len = L-1;\n                a = (int)(rng() % (uint64_t)(L - len));\n                b = a + len;\n            }\n            if(!(0 <= a && a < b && b < L)) continue;\n\n            int sNode = route[a];\n            int tNode = route[b];\n            long long oldCost = preTime[b] - preTime[a];\n\n            int reached = dijkstra_until(sNode, [&](int v){ return v==tNode; });\n            if(reached != tNode) continue;\n            long long newCost = dist[tNode];\n            if(newCost >= oldCost) continue;\n\n            vector<int> path;\n            int cur = tNode;\n            while(cur != -1){\n                path.push_back(cur);\n                if(cur == sNode) break;\n                cur = prevv[cur];\n            }\n            reverse(path.begin(), path.end());\n            if(path.empty() || path.front()!=sNode) continue;\n\n            vector<uint64_t> mid(W64, 0ULL);\n            for(int v: path){\n                const uint64_t* vb = &visFlat[(size_t)v * W64];\n                for(int k=0;k<W64;k++) mid[k] |= vb[k];\n            }\n\n            bool ok = true;\n            for(int k=0;k<W64;k++){\n                uint64_t left  = (a>0) ? pref[(size_t)(a-1)*W64 + k] : 0ULL;\n                uint64_t right = (b+1<L) ? suf[(size_t)(b+1)*W64 + k] : 0ULL;\n                if((left | mid[k] | right) != allMask[k]) { ok=false; break; }\n            }\n            if(!ok) continue;\n\n            long long candT = totalT - oldCost + newCost;\n            if(candT <= 0 || candT >= bestT) continue;\n\n            vector<int> nr;\n            nr.reserve(route.size() - (b - a + 1) + path.size());\n            nr.insert(nr.end(), route.begin(), route.begin()+a);\n            nr.insert(nr.end(), path.begin(), path.end());\n            nr.insert(nr.end(), route.begin()+b+1, route.end());\n\n            route.swap(nr);\n            bestT = candT;\n            rebuild_aux(route);\n        }\n\n        return route;\n    }\n\n    string route_to_moves(const vector<int>& route) const {\n        string out;\n        out.reserve(route.size() ? route.size()-1 : 0);\n        for(size_t i=1;i<route.size();i++){\n            int a=route[i-1], b=route[i];\n            int x1=xs[a], y1=ys[a], x2=xs[b], y2=ys[b];\n            if(x2==x1-1 && y2==y1) out.push_back('U');\n            else if(x2==x1+1 && y2==y1) out.push_back('D');\n            else if(x2==x1 && y2==y1-1) out.push_back('L');\n            else if(x2==x1 && y2==y1+1) out.push_back('R');\n        }\n        return out;\n    }\n\n    void solve() {\n        read();\n        build_nodes();\n        build_segments();\n        build_segment_graph();\n        build_visibility_bitsets();\n\n        // deterministic seed from input\n        uint64_t h = 0x123456789abcdef0ULL;\n        h = splitmix64(h ^ (uint64_t)N);\n        h = splitmix64(h ^ (uint64_t)si * 1315423911ULL ^ (uint64_t)sj * 2654435761ULL);\n        for(int i=0;i<N;i++) for(char ch: c[i]) h = splitmix64(h ^ (uint64_t)(unsigned char)ch);\n        XorShift64 rng(h);\n\n        int startId = id[si][sj];\n        TimeKeeper tk(2.95);\n\n        // dist from start\n        vector<int> distS(R, INF), prevTmp(R, -1);\n        dijkstra_store(startId, prevTmp.data(), distS.data());\n\n        // segment min distance\n        vector<int> segMinH(H, INF), segMinV(V, INF);\n        for(int node=0; node<R; node++){\n            segMinH[hseg[node]] = min(segMinH[hseg[node]], distS[node]);\n            segMinV[vseg[node]] = min(segMinV[vseg[node]], distS[node]);\n        }\n        int maxDegH = 0, maxDegV = 0, maxLenH = 0, maxLenV = 0;\n        for(int hh=0; hh<H; hh++){ maxDegH = max(maxDegH, degH[hh]); maxLenH = max(maxLenH, lenH[hh]); }\n        for(int vv=0; vv<V; vv++){ maxDegV = max(maxDegV, degV[vv]); maxLenV = max(maxLenV, lenV[vv]); }\n\n        // --- cover generation (rollback lexicographic) ---\n        vector<pair<vector<char>, vector<char>>> covers;\n        covers.reserve(32);\n        covers.push_back(compute_min_vertex_cover_card(false, rng));\n        for(int i=0;i<11;i++) covers.push_back(compute_min_vertex_cover_card(true, rng));\n\n        auto make_weight_cover = [&](int scaleDist, int modeDeg, int coefDeg, int coefLen, int noiseAmp){\n            vector<long long> wH(H), wV(V);\n            for(int hh=0; hh<H; hh++){\n                long long base = (long long)(segMinH[hh] + 1) * scaleDist;\n                if(modeDeg == 1) base += (long long)coefDeg * (maxDegH - degH[hh]);\n                if(modeDeg == 2) base += (long long)coefDeg * degH[hh];\n                base += (long long)coefLen * (maxLenH - lenH[hh]);\n                if(noiseAmp) base += rng.next_int(0, noiseAmp);\n                wH[hh] = max(1LL, base);\n            }\n            for(int vv=0; vv<V; vv++){\n                long long base = (long long)(segMinV[vv] + 1) * scaleDist;\n                if(modeDeg == 1) base += (long long)coefDeg * (maxDegV - degV[vv]);\n                if(modeDeg == 2) base += (long long)coefDeg * degV[vv];\n                base += (long long)coefLen * (maxLenV - lenV[vv]);\n                if(noiseAmp) base += rng.next_int(0, noiseAmp);\n                wV[vv] = max(1LL, base);\n            }\n            return compute_min_vertex_cover_weighted(wH, wV);\n        };\n\n        covers.push_back(make_weight_cover(1, 0, 0, 0, 600));\n        covers.push_back(make_weight_cover(2, 0, 0, 0, 900));\n        covers.push_back(make_weight_cover(1, 1, 55, 0, 800));\n        covers.push_back(make_weight_cover(1, 2, 45, 0, 800));\n        covers.push_back(make_weight_cover(1, 0, 0, 12, 600));\n        covers.push_back(make_weight_cover(2, 1, 40, 6, 750));\n        covers.push_back(make_weight_cover(3, 0, 0, 0, 1200));\n        covers.push_back(make_weight_cover(2, 2, 35, 8, 900));\n\n        // --- plan generation + dedup ---\n        struct Plan { long long est; vector<int> wp; };\n        vector<Plan> plans;\n        plans.reserve(covers.size() * 4);\n\n        unordered_set<uint64_t> seenPlans;\n        seenPlans.reserve(4096);\n\n        auto hash_wp = [&](const vector<int>& wp)->uint64_t{\n            uint64_t x = 1469598103934665603ULL;\n            for(int v: wp){\n                x ^= (uint64_t)(uint32_t)v;\n                x *= 1099511628211ULL;\n                x ^= (x >> 32);\n            }\n            return x;\n        };\n\n        auto try_push_plan = [&](vector<int>&& wp){\n            int m = (int)wp.size();\n            if(m <= 1) return;\n            if(m > 92) return;\n            uint64_t key = hash_wp(wp);\n            if(seenPlans.find(key) != seenPlans.end()) return;\n            seenPlans.insert(key);\n\n            long long sumD = 0;\n            int mx = 0;\n            for(int i=1;i<m;i++){\n                sumD += distS[wp[i]];\n                mx = max(mx, distS[wp[i]]);\n            }\n            long long alpha = 470;\n            long long est = alpha * (long long)m + sumD + 2LL * mx;\n            plans.push_back({est, std::move(wp)});\n        };\n\n        for(auto &cv : covers){\n            if(tk.remaining() < 1.75) break;\n            vector<char> needH = cv.first, needV = cv.second;\n            needH[hseg[startId]] = 0;\n            needV[vseg[startId]] = 0;\n\n            int cntNeed=0;\n            for(char x: needH) cntNeed += (x!=0);\n            for(char x: needV) cntNeed += (x!=0);\n            if(cntNeed==0){\n                needH.assign(H, 1);\n                needV.assign(V, 0);\n                needH[hseg[startId]] = 0;\n            }\n\n            try_push_plan(build_waypoints_unpaired(needH, needV, startId, distS, false, rng));\n            try_push_plan(build_waypoints_paired  (needH, needV, startId, distS, false, rng));\n            try_push_plan(build_waypoints_unpaired(needH, needV, startId, distS, true,  rng));\n            try_push_plan(build_waypoints_paired  (needH, needV, startId, distS, true,  rng));\n        }\n\n        sort(plans.begin(), plans.end(), [&](const Plan& a, const Plan& b){ return a.est < b.est; });\n        int planKeep = min<int>(36, (int)plans.size());\n        plans.resize(planKeep);\n\n        // --- evaluate plans (APSP+prevs), keep best candidates ---\n        struct Cand {\n            long long cycleCost;\n            vector<int> wp, seq, prevs, Dflat;\n            int m;\n        };\n        vector<Cand> cands;\n        int candKeep = 18;\n        vector<int> distRowBuf;\n\n        for(int pi=0; pi<planKeep; pi++){\n            if(tk.remaining() < 0.95) break;\n            auto &wp = plans[pi].wp;\n            int m = (int)wp.size();\n            if(m <= 1) continue;\n\n            vector<int> Dflat, prevs;\n            build_apsp_with_prevs(wp, Dflat, prevs, distRowBuf);\n\n            vector<int> s1 = init_nearest_neighbor(Dflat, m);\n            vector<int> s2 = init_cheapest_insertion(Dflat, m);\n\n            vector<int> s3(m);\n            iota(s3.begin(), s3.end(), 0);\n            for(int i=1;i<m;i++){\n                int j = 1 + (int)(rng() % (uint64_t)(m-1));\n                swap(s3[i], s3[j]);\n            }\n\n            double baseTime = 0.010 + 0.00008 * m;\n            baseTime = min(baseTime, 0.020);\n\n            optimize_waypoint_order_sa(s1, Dflat, m, baseTime, rng);\n            optimize_waypoint_order_sa(s2, Dflat, m, baseTime, rng);\n            optimize_waypoint_order_sa(s3, Dflat, m, baseTime, rng);\n\n            long long c1 = cycle_cost(s1, Dflat, m);\n            long long c2 = cycle_cost(s2, Dflat, m);\n            long long c3 = cycle_cost(s3, Dflat, m);\n\n            vector<int> bestSeq;\n            long long bestC;\n            if(c2 <= c1 && c2 <= c3){ bestSeq = std::move(s2); bestC = c2; }\n            else if(c1 <= c2 && c1 <= c3){ bestSeq = std::move(s1); bestC = c1; }\n            else { bestSeq = std::move(s3); bestC = c3; }\n\n            cands.push_back(Cand{bestC, wp, std::move(bestSeq), std::move(prevs), std::move(Dflat), m});\n            if((int)cands.size() > candKeep){\n                auto it = max_element(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                    return a.cycleCost < b.cycleCost;\n                });\n                cands.erase(it);\n            }\n        }\n\n        if(cands.empty()){\n            vector<int> route = {startId};\n            if(R > 1 && deg[startId]){\n                int nb = nbr[startId][0];\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n            cout << route_to_moves(route) << \"\\n\";\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){ return a.cycleCost < b.cycleCost; });\n\n        int K = min<int>(5, (int)cands.size());\n        vector<int> bestRoute;\n        long long bestT = (1LL<<60);\n\n        // Keep good selection while leaving lots of time for final shortcuts (now more efficient).\n        double quickTotal = min(1.25, max(0.35, tk.remaining() * 0.42));\n        double per = quickTotal / K;\n\n        for(int i=0;i<K;i++){\n            auto cand = std::move(cands[i]);\n\n            double saTime = min(0.16, max(0.04, per * 0.35));\n            optimize_waypoint_order_sa(cand.seq, cand.Dflat, cand.m, saTime, rng);\n\n            vector<int> route = expand_route_from_seq(cand.wp, cand.seq, cand.prevs);\n            if(route.size()==1 && R>1 && deg[startId]){\n                int nb = nbr[startId][0];\n                route.push_back(nb);\n                route.push_back(startId);\n            }\n\n            double cutTime = max(0.01, per - saTime);\n            route = improve_by_shortcuts_full_fast(std::move(route), cutTime, rng);\n\n            auto [ok, t] = eval_full_visibility(route);\n            if(ok && t < bestT){\n                bestT = t;\n                bestRoute.swap(route);\n            }\n        }\n\n        double rem = tk.remaining();\n        if(rem > 0.02){\n            bestRoute = improve_by_shortcuts_full_fast(std::move(bestRoute), rem, rng);\n        }\n\n        if(bestRoute.size()==1 && R>1 && deg[startId]){\n            int nb = nbr[startId][0];\n            bestRoute.push_back(nb);\n            bestRoute.push_back(startId);\n        }\n\n        cout << route_to_moves(bestRoute) << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n    Solver s;\n    s.solve();\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    if (x < lo) return lo;\n    if (x > hi) return hi;\n    return x;\n}\n\nstruct Item {\n    long long key;\n    int id;\n};\nstruct ItemCmp {\n    bool operator()(const Item& a, const Item& b) const { return a.key < b.key; } // max-heap\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K, R;\n    cin >> N >> M >> K >> R;\n\n    vector<vector<int>> d(N, vector<int>(K));\n    for (int i = 0; i < N; i++) for (int k = 0; k < K; k++) cin >> d[i][k];\n\n    vector<vector<int>> g(N);\n    vector<int> indeg(N, 0), outdeg(N, 0);\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u; --v;\n        g[u].push_back(v);\n        indeg[v]++;\n        outdeg[u]++;\n    }\n\n    // Critical path length (#tasks); u < v so reverse index DP works\n    vector<int> cp(N, 1);\n    for (int i = N - 1; i >= 0; i--) {\n        int best = 1;\n        for (int v : g[i]) best = max(best, 1 + cp[v]);\n        cp[i] = best;\n    }\n\n    // Difficulty proxy\n    vector<int> diff(N, 0);\n    for (int i = 0; i < N; i++) {\n        int s = 0;\n        for (int k = 0; k < K; k++) s += d[i][k];\n        diff[i] = s;\n    }\n\n    // Static priority key for extraction\n    vector<long long> key(N);\n    for (int i = 0; i < N; i++) {\n        key[i] = (long long)cp[i] * 1'000'000LL\n               + (long long)diff[i] * 1'000LL\n               + (long long)outdeg[i] * 10LL\n               - (long long)i;\n    }\n\n    // Task state: 0 not started, 1 running, 2 done\n    vector<int> state(N, 0);\n\n    // Ready management\n    vector<char> in_ready(N, 0);\n    vector<int> ready_since(N, 0);\n    priority_queue<Item, vector<Item>, ItemCmp> pq_key;\n    priority_queue<Item, vector<Item>, ItemCmp> pq_age; // key = -ready_since\n\n    auto push_ready = [&](int task, int day_ready) {\n        if (state[task] != 0) return;\n        if (indeg[task] != 0) return;\n        if (in_ready[task]) return;\n        in_ready[task] = 1;\n        ready_since[task] = day_ready;\n        pq_key.push({key[task], task});\n        pq_age.push({-(long long)day_ready, task});\n    };\n\n    for (int i = 0; i < N; i++) if (indeg[i] == 0) push_ready(i, 0);\n\n    // Member state\n    vector<int> member_task(M, -1);\n    vector<int> member_start(M, -1);\n\n    // Skill estimates\n    const double SKILL_INIT = 10.0;\n    const double SKILL_MIN  = 0.0;\n    const double SKILL_MAX  = 80.0;\n    vector<vector<double>> shat(M, vector<double>(K, SKILL_INIT));\n    vector<int> samples(M, 0);\n\n    auto predict_w = [&](int task, int mem) -> double {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double def = (double)d[task][k] - shat[mem][k];\n            if (def > 0) w += def;\n        }\n        return w;\n    };\n\n    // Conservative predictor for scheduling\n    auto predict_time = [&](int task, int mem) -> double {\n        double w = predict_w(task, mem);\n        double uncert = (1.5 + 0.01 * w) / sqrt(1.0 + samples[mem]);\n        return max(1.0, w + 0.6 + uncert);\n    };\n\n    // Noise-aware interval update\n    auto update_skill_interval = [&](int mem, int task, int t_obs) {\n        double lo, hi;\n        if (t_obs <= 1) {\n            lo = 0.0;\n            hi = 4.0;  // t==1 can still happen with w>0 due to negative noise\n        } else {\n            lo = max(1.0, (double)t_obs - 3.0);\n            hi = (double)t_obs + 3.0;\n        }\n\n        vector<double> def(K);\n        vector<int> active;\n        active.reserve(K);\n        double w_hat = 0.0;\n        for (int k = 0; k < K; k++) {\n            def[k] = max(0.0, (double)d[task][k] - shat[mem][k]);\n            if (def[k] > 1e-12) active.push_back(k);\n            w_hat += def[k];\n        }\n\n        if (lo - 1e-9 <= w_hat && w_hat <= hi + 1e-9) return;\n\n        double lr = 0.8 / sqrt(1.0 + samples[mem]);\n\n        if (w_hat > hi) {\n            if (active.empty()) return;\n            double need = w_hat - hi;\n            double step = lr * need;\n            for (int k : active) {\n                double frac = def[k] / w_hat;\n                double inc = step * frac;\n                inc = min(inc, def[k]);\n                shat[mem][k] = clampd(shat[mem][k] + inc, SKILL_MIN, SKILL_MAX);\n            }\n        } else { // w_hat < lo\n            double need = lo - w_hat;\n            double step = lr * need;\n\n            if (!active.empty()) {\n                double denom = 0.0;\n                for (int k : active) denom += (def[k] + 1.0);\n                for (int k : active) {\n                    double frac = (def[k] + 1.0) / denom;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            } else {\n                double denom = 1e-9;\n                for (int k = 0; k < K; k++) denom += (double)d[task][k] + 1.0;\n                for (int k = 0; k < K; k++) {\n                    double frac = ((double)d[task][k] + 1.0) / denom;\n                    double dec = step * frac;\n                    shat[mem][k] = clampd(shat[mem][k] - dec, SKILL_MIN, SKILL_MAX);\n                }\n            }\n        }\n    };\n\n    mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\n    // Candidate sizes (close to the good runs)\n    const int CKEY = 210;\n    const int CAGE = 110;\n\n    for (int day = 1; day <= 2000; day++) {\n        // Free members\n        vector<int> free_m;\n        free_m.reserve(M);\n        vector<char> is_free(M, 0);\n        for (int j = 0; j < M; j++) {\n            if (member_task[j] == -1) {\n                free_m.push_back(j);\n                is_free[j] = 1;\n            }\n        }\n        int F = (int)free_m.size();\n        shuffle(free_m.begin(), free_m.end(), rng);\n\n        // Extract candidates from PQs\n        vector<int> cand;\n        cand.reserve(CKEY + CAGE);\n\n        vector<pair<long long,int>> popped_key, popped_age;\n        popped_key.reserve(CKEY * 2);\n        popped_age.reserve(CAGE * 2);\n\n        vector<char> usedC(N, 0);\n        auto take_from = [&](auto &pq, int limit, vector<pair<long long,int>> &popped) {\n            while (!pq.empty() && (int)cand.size() < limit) {\n                auto it = pq.top(); pq.pop();\n                popped.push_back({it.key, it.id});\n                int t = it.id;\n                if (state[t] != 0 || indeg[t] != 0 || !in_ready[t]) continue;\n                if (usedC[t]) continue;\n                usedC[t] = 1;\n                cand.push_back(t);\n            }\n        };\n        take_from(pq_key, CKEY, popped_key);\n        take_from(pq_age, CKEY + CAGE, popped_age);\n\n        vector<pair<int,int>> assigns;\n\n        if (F > 0 && !cand.empty()) {\n            const double eps = 1e-9;\n            int Tn0 = (int)cand.size();\n\n            // Precompute predicted times for all members for each candidate task\n            vector<vector<double>> tCand(Tn0, vector<double>(M, 1.0));\n            vector<double> best_all(Tn0, 1.0), second_all(Tn0, 1.0), avg_free(Tn0, 1.0), best_free(Tn0, 1.0);\n            vector<int> count_good(Tn0, 1), best_mem(Tn0, 0);\n\n            for (int j = 0; j < Tn0; j++) {\n                int task = cand[j];\n\n                double b1 = 1e100, b2 = 1e100;\n                int bm = 0;\n                for (int m = 0; m < M; m++) {\n                    double t = predict_time(task, m);\n                    tCand[j][m] = t;\n                    if (t < b1) { b2 = b1; b1 = t; bm = m; }\n                    else if (t < b2) { b2 = t; }\n                }\n                best_all[j] = b1;\n                second_all[j] = b2;\n                best_mem[j] = bm;\n\n                int cg = 0;\n                double thr = b1 * 1.30 + 1e-6;\n                for (int m = 0; m < M; m++) if (tCand[j][m] <= thr) cg++;\n                count_good[j] = max(1, cg);\n\n                double sum = 0.0, bf = 1e100;\n                for (int mem : free_m) {\n                    double t = tCand[j][mem];\n                    sum += t;\n                    bf = min(bf, t);\n                }\n                avg_free[j] = sum / (double)F;\n                best_free[j] = bf;\n            }\n\n            // Soft gating: defer hard+specialized tasks if no good free member, but only while young.\n            vector<int> cand2; cand2.reserve(Tn0);\n            vector<int> deferred; deferred.reserve(Tn0);\n\n            for (int j = 0; j < Tn0; j++) {\n                int task = cand[j];\n                double b = best_all[j] + eps;\n                double s = second_all[j] + eps;\n                double age = (double)(day - ready_since[task]);\n\n                bool hard = (b >= 28.0);\n                bool specialized = (count_good[j] <= 2) && (s / b >= 1.35);\n                bool no_good_free = (best_free[j] / b >= 1.35);\n\n                bool gate = hard && specialized && no_good_free && (age < 140.0);\n\n                if (gate) deferred.push_back(j);\n                else cand2.push_back(j);\n            }\n\n            // Fallback: avoid idling by re-allowing deferred tasks by age (oldest first)\n            int target = min(F, Tn0);\n            if ((int)cand2.size() < target && !deferred.empty()) {\n                sort(deferred.begin(), deferred.end(), [&](int a, int b){\n                    return ready_since[cand[a]] < ready_since[cand[b]];\n                });\n                for (int j : deferred) {\n                    if ((int)cand2.size() >= target) break;\n                    cand2.push_back(j);\n                }\n            }\n\n            int Tn = (int)cand2.size();\n            int flow_need = min(F, Tn);\n\n            if (flow_need > 0) {\n                auto weight_pair = [&](int mem, int jIdx) -> double {\n                    int task = cand[jIdx];\n                    double pt = tCand[jIdx][mem];\n\n                    double pr = (double)cp[task]\n                              + 0.03 * (double)outdeg[task]\n                              + 0.001 * (double)diff[task];\n\n                    double age = (double)(day - ready_since[task]);\n                    double age_coef = (day < 1200 ? 0.0008 : 0.00115);\n                    double age_bonus = age_coef * age;\n\n                    double explore = 0.02 / sqrt(1.0 + samples[mem]);\n                    double adv = 0.10 * ((avg_free[jIdx] - pt) / (avg_free[jIdx] + eps));\n                    double len_pen = 0.00055 * pt;\n\n                    // Specialization-aware mismatch penalty (catastrophe avoidance)\n                    double b = best_all[jIdx] + eps;\n                    double ratio = pt / b;\n                    double mismatch_pen = 0.0;\n                    if (ratio > 1.20) {\n                        double bf = ratio - 1.20;\n                        double bfq = bf * bf;\n\n                        double scar = (second_all[jIdx] - best_all[jIdx]) / b;\n                        scar = clampd(scar, 0.0, 2.0);\n\n                        double good_factor = 1.0 + 0.30 * (3.0 / (double)min(3, count_good[jIdx]));\n                        double scar_factor = 1.0 + 0.60 * scar;\n\n                        double hardf = min(1.0, best_all[jIdx] / 80.0);\n\n                        double age_relax = 1.0 / (1.0 + age / 200.0);\n                        double crit = min(1.0, (double)cp[task] / 40.0);\n                        double crit_scale = 1.0 - 0.50 * crit; // [0.5,1]\n\n                        double lambda = 0.95;\n                        mismatch_pen = lambda * hardf * scar_factor * good_factor * age_relax * crit_scale * (bfq * 4.0);\n                    }\n\n                    return pr / pow(max(1.0, pt), 0.85) + age_bonus + explore + adv\n                         - mismatch_pen - len_pen;\n                };\n\n                // Build weights and shift to non-negative costs (ACL requirement)\n                vector<vector<double>> W(F, vector<double>(Tn, 0.0));\n                double maxW = -1e100;\n                for (int i = 0; i < F; i++) {\n                    int mem = free_m[i];\n                    for (int j = 0; j < Tn; j++) {\n                        int jIdx = cand2[j];\n                        double w = weight_pair(mem, jIdx);\n                        W[i][j] = w;\n                        maxW = max(maxW, w);\n                    }\n                }\n                if (!(maxW > -1e50)) maxW = 0.0;\n\n                const double SCALE = 1e6;\n                int S = 0;\n                int mem0 = 1;\n                int task0 = mem0 + F;\n                int TT = task0 + Tn;\n\n                atcoder::mcf_graph<int, long long> mcf(TT + 1);\n                for (int i = 0; i < F; i++) mcf.add_edge(S, mem0 + i, 1, 0);\n                for (int j = 0; j < Tn; j++) mcf.add_edge(task0 + j, TT, 1, 0);\n\n                struct Rec { int eid, mem, task; };\n                vector<Rec> rec;\n                rec.reserve((size_t)F * Tn);\n\n                for (int i = 0; i < F; i++) {\n                    int mem = free_m[i];\n                    for (int j = 0; j < Tn; j++) {\n                        double c = (maxW - W[i][j]) * SCALE;\n                        long long cost = (long long)llround(c);\n                        if (cost < 0) cost = 0;\n                        int eid = mcf.add_edge(mem0 + i, task0 + j, 1, cost);\n                        rec.push_back({eid, mem, cand[cand2[j]]});\n                    }\n                }\n\n                mcf.flow(S, TT, flow_need);\n                auto edges = mcf.edges();\n                for (auto &e : rec) if (edges[e.eid].flow == 1) assigns.push_back({e.mem, e.task});\n\n                for (auto [mem, task] : assigns) {\n                    state[task] = 1;\n                    in_ready[task] = 0;\n                    member_task[mem] = task;\n                    member_start[mem] = day;\n                }\n            }\n        }\n\n        // Repush popped entries still ready and not assigned today\n        vector<char> assigned_today(N, 0);\n        for (auto [m, t] : assigns) assigned_today[t] = 1;\n\n        auto repush = [&](auto &pq, const vector<pair<long long,int>> &popped) {\n            for (auto &e : popped) {\n                int t = e.second;\n                if (state[t] == 0 && indeg[t] == 0 && in_ready[t] && !assigned_today[t]) {\n                    pq.push({e.first, t});\n                }\n            }\n        };\n        repush(pq_key, popped_key);\n        repush(pq_age, popped_age);\n\n        // Output\n        cout << assigns.size();\n        for (auto [mem, task] : assigns) cout << ' ' << (mem + 1) << ' ' << (task + 1);\n        cout << '\\n' << flush;\n\n        // Read completion info\n        int nfin;\n        cin >> nfin;\n        if (nfin == -1) return 0;\n\n        for (int i = 0; i < nfin; i++) {\n            int f; cin >> f; --f;\n            int task = member_task[f];\n            int st = member_start[f];\n            int t_obs = day - st + 1;\n\n            update_skill_interval(f, task, t_obs);\n            samples[f]++;\n\n            member_task[f] = -1;\n            member_start[f] = -1;\n\n            state[task] = 2;\n            for (int v : g[task]) {\n                indeg[v]--;\n                if (indeg[v] == 0 && state[v] == 0) push_ready(v, day);\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Order { int ax, ay, cx, cy; };\nstruct Point { int x, y; };\nstatic inline int distMan(const Point& a, const Point& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\nstatic const Point OFFICE{400, 400};\n\nstruct Node {\n    int id;\n    uint8_t tp; // 0 pickup, 1 delivery\n};\n\nstruct RNG {\n    uint64_t s;\n    explicit RNG(uint64_t seed) : s(seed) {}\n    static inline uint64_t splitmix64(uint64_t &x) {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    inline uint64_t next_u64() { return splitmix64(s); }\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct BestState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    int cost = INT_MAX;\n};\n\nstruct CurState {\n    array<int,50> sel{};\n    array<Node,100> seq{};\n    array<Point,102> pts{}; // OFFICE + 100 nodes + OFFICE\n    int cost = INT_MAX;\n\n    array<int,1000> pickPos;\n    array<int,1000> delPos;\n    array<uint8_t,1000> selected;\n};\n\nstatic inline Point nodePoint(const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              const Node& nd) {\n    return (nd.tp == 0 ? pickPt[nd.id] : delPt[nd.id]);\n}\n\nstatic inline int computeCostFromPts(const array<Point,102>& pts) {\n    int c = 0;\n    for (int i = 0; i < 101; i++) c += distMan(pts[i], pts[i+1]);\n    return c;\n}\n\nstatic void buildPtsAndPos(CurState& st,\n                           const array<Point,1000>& pickPt,\n                           const array<Point,1000>& delPt) {\n    st.pts[0] = OFFICE;\n    for (int i = 0; i < 100; i++) st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[101] = OFFICE;\n    st.cost = computeCostFromPts(st.pts);\n\n    st.pickPos.fill(-1);\n    st.delPos.fill(-1);\n    for (int i = 0; i < 100; i++) {\n        const Node &nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n}\n\nstatic array<Node,100> buildGreedyInterleaving(const array<Point,1000>& pickPt,\n                                               const array<Point,1000>& delPt,\n                                               const array<int,50>& sel) {\n    vector<int> unpicked; unpicked.reserve(50);\n    for (int i = 0; i < 50; i++) unpicked.push_back(sel[i]);\n    vector<int> carrying; carrying.reserve(50);\n\n    array<Node,100> seq;\n    Point cur = OFFICE;\n\n    auto erase_by_swap_back = [](vector<int>& v, int idx) {\n        v[idx] = v.back();\n        v.pop_back();\n    };\n\n    for (int t = 0; t < 100; t++) {\n        int bestDist = INT_MAX, bestId = -1, bestType = -1, bestIdx = -1;\n\n        for (int i = 0; i < (int)unpicked.size(); i++) {\n            int id = unpicked[i];\n            int d = distMan(cur, pickPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 0; bestIdx = i; }\n        }\n        for (int i = 0; i < (int)carrying.size(); i++) {\n            int id = carrying[i];\n            int d = distMan(cur, delPt[id]);\n            if (d < bestDist) { bestDist = d; bestId = id; bestType = 1; bestIdx = i; }\n        }\n\n        if (bestType == 0) {\n            seq[t] = Node{bestId, 0};\n            cur = pickPt[bestId];\n            carrying.push_back(bestId);\n            erase_by_swap_back(unpicked, bestIdx);\n        } else {\n            seq[t] = Node{bestId, 1};\n            cur = delPt[bestId];\n            erase_by_swap_back(carrying, bestIdx);\n        }\n    }\n    return seq;\n}\n\n// ----------------- Fixed-size insertion utils -----------------\nstruct Seq {\n    array<Node,100> a;\n    int len = 0;\n};\n\nstatic inline Seq buildBaseFromSkip(const array<Node,100>& seq, const vector<int>& skipPosSorted) {\n    Seq base;\n    int ptr = 0;\n    int m = (int)skipPosSorted.size();\n    for (int i = 0; i < 100; i++) {\n        if (ptr < m && skipPosSorted[ptr] == i) { ptr++; continue; }\n        base.a[base.len++] = seq[i];\n    }\n    return base;\n}\n\n// Best insertion of pickup+delivery into base (pickup before delivery).\nstatic inline pair<Seq,int> bestInsertPairFixed(const Seq& base,\n                                                const Point& pick,\n                                                const Point& del,\n                                                int idToInsert,\n                                                const array<Point,1000>& pickPt,\n                                                const array<Point,1000>& delPt) {\n    const int L = base.len;\n    array<Point,102> pts;\n    pts[0] = OFFICE;\n    for (int i = 0; i < L; i++) pts[i+1] = nodePoint(pickPt, delPt, base.a[i]);\n    pts[L+1] = OFFICE;\n\n    int baseCost = 0;\n    for (int i = 0; i < L+1; i++) baseCost += distMan(pts[i], pts[i+1]);\n\n    int bestDelta = INT_MAX;\n    int bestP = 0;\n    int bestD = 1;\n\n    for (int p = 0; p <= L; p++) {\n        int delta1 = distMan(pts[p], pick) + distMan(pick, pts[p+1]) - distMan(pts[p], pts[p+1]);\n        for (int dpos = p+1; dpos <= L+1; dpos++) {\n            Point left, right;\n            if (dpos == p+1) { left = pick; right = pts[p+1]; }\n            else { left = pts[dpos-1]; right = pts[dpos]; }\n            int delta2 = distMan(left, del) + distMan(del, right) - distMan(left, right);\n            int tot = delta1 + delta2;\n            if (tot < bestDelta) {\n                bestDelta = tot;\n                bestP = p;\n                bestD = dpos;\n            }\n        }\n    }\n\n    Seq res;\n    res.len = L + 2;\n    for (int idx = 0; idx < res.len; idx++) {\n        if (idx < bestP) res.a[idx] = base.a[idx];\n        else if (idx == bestP) res.a[idx] = Node{idToInsert, 0};\n        else if (idx < bestD) res.a[idx] = base.a[idx-1];\n        else if (idx == bestD) res.a[idx] = Node{idToInsert, 1};\n        else res.a[idx] = base.a[idx-2];\n    }\n    return {res, baseCost + bestDelta};\n}\n\nstatic inline pair<Seq,int> insertSequenceFixed(const Seq& base,\n                                                const vector<int>& ids,\n                                                const array<Point,1000>& pickPt,\n                                                const array<Point,1000>& delPt) {\n    Seq cur = base;\n    int cost = 0;\n    for (int id : ids) {\n        auto res = bestInsertPairFixed(cur, pickPt[id], delPt[id], id, pickPt, delPt);\n        cur = res.first;\n        cost = res.second;\n    }\n    return {cur, cost};\n}\n\nstatic inline pair<Seq,int> bestPermutationInsertKFixed(const Seq& base,\n                                                        vector<int> ids,\n                                                        const array<Point,1000>& pickPt,\n                                                        const array<Point,1000>& delPt) {\n    sort(ids.begin(), ids.end());\n    Seq bestNodes;\n    int bestCost = INT_MAX;\n    do {\n        auto [nodes, cost] = insertSequenceFixed(base, ids, pickPt, delPt);\n        if (cost < bestCost) { bestCost = cost; bestNodes = nodes; }\n    } while (next_permutation(ids.begin(), ids.end()));\n    return {bestNodes, bestCost};\n}\n\n// ----------------- Local move helpers -----------------\nstatic inline void applyRelocate(array<Node,100>& a, int i, int j) {\n    if (i == j) return;\n    Node tmp = a[i];\n    if (i < j) {\n        for (int k = i; k < j; k++) a[k] = a[k+1];\n        a[j] = tmp;\n    } else {\n        for (int k = i; k > j; k--) a[k] = a[k-1];\n        a[j] = tmp;\n    }\n}\n\nstatic inline int deltaSwapPts(const array<Point,102>& pts, int i, int j) {\n    int a = i + 1, b = j + 1;\n    auto getPt = [&](int idx)->Point {\n        if (idx == a) return pts[b];\n        if (idx == b) return pts[a];\n        return pts[idx];\n    };\n    int edges[4] = {a-1, a, b-1, b};\n    sort(edges, edges+4);\n    int oldc = 0, newc = 0;\n    int last = -999;\n    for (int k = 0; k < 4; k++) {\n        int e = edges[k];\n        if (e == last) continue;\n        last = e;\n        if (0 <= e && e <= 100) {\n            oldc += distMan(pts[e], pts[e+1]);\n            newc += distMan(getPt(e), getPt(e+1));\n        }\n    }\n    return newc - oldc;\n}\n\nstatic inline int deltaRelocatePts(const array<Point,102>& pts, int i, int j) {\n    const Point& X = pts[i+1];\n    const Point& A = pts[i];\n    const Point& B = pts[i+2];\n    int delta_rem = distMan(A, B) - distMan(A, X) - distMan(X, B);\n    Point C, D;\n    if (i < j) { C = pts[j+1]; D = pts[j+2]; }\n    else { C = pts[j]; D = pts[j+1]; }\n    int delta_ins = distMan(C, X) + distMan(X, D) - distMan(C, D);\n    return delta_rem + delta_ins;\n}\n\nstatic inline bool canRelocateOrderConstraint(const CurState& st, int i, int j) {\n    const Node& nd = st.seq[i];\n    int id = nd.id;\n    int p = st.pickPos[id];\n    int d = st.delPos[id];\n    int other = (nd.tp == 0 ? d : p);\n\n    int new_other = other;\n    if (i < j) {\n        if (other >= i + 1 && other <= j) new_other = other - 1;\n    } else {\n        if (other >= j && other <= i - 1) new_other = other + 1;\n    }\n    return (nd.tp == 0) ? (j < new_other) : (new_other < j);\n}\n\nstatic inline bool canSwapOrderConstraint(const CurState& st, int i, int j) {\n    const Node& a = st.seq[i];\n    const Node& b = st.seq[j];\n    if (a.id == b.id) return false;\n\n    {\n        int id = a.id;\n        int np = (a.tp == 0 ? j : st.pickPos[id]);\n        int nd = (a.tp == 1 ? j : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    {\n        int id = b.id;\n        int np = (b.tp == 0 ? i : st.pickPos[id]);\n        int nd = (b.tp == 1 ? i : st.delPos[id]);\n        if (!(np < nd)) return false;\n    }\n    return true;\n}\n\nstatic void updateRangeAfterRelocate(CurState& st,\n                                     const array<Point,1000>& pickPt,\n                                     const array<Point,1000>& delPt,\n                                     int l, int r) {\n    for (int k = l; k <= r; k++) {\n        st.pts[k+1] = nodePoint(pickPt, delPt, st.seq[k]);\n        const Node& nd = st.seq[k];\n        if (nd.tp == 0) st.pickPos[nd.id] = k;\n        else st.delPos[nd.id] = k;\n    }\n}\n\nstatic void updateAfterSwap(CurState& st,\n                            const array<Point,1000>& pickPt,\n                            const array<Point,1000>& delPt,\n                            int i, int j) {\n    st.pts[i+1] = nodePoint(pickPt, delPt, st.seq[i]);\n    st.pts[j+1] = nodePoint(pickPt, delPt, st.seq[j]);\n    {\n        const Node& nd = st.seq[i];\n        if (nd.tp == 0) st.pickPos[nd.id] = i;\n        else st.delPos[nd.id] = i;\n    }\n    {\n        const Node& nd = st.seq[j];\n        if (nd.tp == 0) st.pickPos[nd.id] = j;\n        else st.delPos[nd.id] = j;\n    }\n}\n\nstatic void greedyImproveRelocate(CurState& st,\n                                  const array<Point,1000>& pickPt,\n                                  const array<Point,1000>& delPt,\n                                  RNG& rng,\n                                  int iters) {\n    for (int it = 0; it < iters; it++) {\n        int i = rng.next_int(0, 99);\n        int j = rng.next_int(0, 99);\n        if (i == j) continue;\n        if (!canRelocateOrderConstraint(st, i, j)) continue;\n\n        int delta = deltaRelocatePts(st.pts, i, j);\n        if (delta >= 0) continue;\n\n        applyRelocate(st.seq, i, j);\n        int l = min(i, j), r = max(i, j);\n        updateRangeAfterRelocate(st, pickPt, delPt, l, r);\n        st.cost += delta;\n    }\n}\n\nstatic void hillClimbOrderReinsert(CurState& st,\n                                   const array<Point,1000>& pickPt,\n                                   const array<Point,1000>& delPt,\n                                   RNG& rng,\n                                   int attempts) {\n    for (int t = 0; t < attempts; t++) {\n        int idx = rng.next_int(0, 49);\n        int id = st.sel[idx];\n        int pi = st.pickPos[id], di = st.delPos[id];\n        if (!(0 <= pi && pi < di && di < 100)) continue;\n\n        vector<int> skip = {pi, di};\n        sort(skip.begin(), skip.end());\n        Seq base = buildBaseFromSkip(st.seq, skip);\n\n        auto [newSeq, newCost] = bestInsertPairFixed(base, pickPt[id], delPt[id], id, pickPt, delPt);\n        if (newCost < st.cost) {\n            for (int i = 0; i < 100; i++) st.seq[i] = newSeq.a[i];\n            buildPtsAndPos(st, pickPt, delPt);\n        }\n    }\n}\n\n// ----------------- Selection helpers -----------------\nstatic inline int orderIncidentCost(const CurState& st, int id) {\n    int p = st.pickPos[id], d = st.delPos[id];\n    if (!(0 <= p && p < d && d < 100)) return INT_MAX/4;\n    auto edgeSumAtPos = [&](int pos)->int {\n        int idx = pos + 1;\n        return distMan(st.pts[idx-1], st.pts[idx]) + distMan(st.pts[idx], st.pts[idx+1]);\n    };\n    return edgeSumAtPos(p) + edgeSumAtPos(d);\n}\n\nstatic int pickOutIdxBiased(const CurState& st, RNG& rng) {\n    vector<pair<int,int>> v;\n    v.reserve(50);\n    for (int i = 0; i < 50; i++) v.push_back({orderIncidentCost(st, st.sel[i]), i});\n    sort(v.begin(), v.end(), greater<>());\n    int cand = 12;\n    return v[rng.next_int(0, cand-1)].second;\n}\n\nstatic vector<int> pickKOutIndices(const CurState& st, RNG& rng, int k) {\n    vector<pair<int,int>> v;\n    v.reserve(50);\n    for (int i = 0; i < 50; i++) v.push_back({orderIncidentCost(st, st.sel[i]), i});\n    sort(v.begin(), v.end(), greater<>());\n    int cand = min(24, (int)v.size());\n    vector<int> out; out.reserve(k);\n    array<uint8_t,50> used{}; used.fill(0);\n    while ((int)out.size() < k) {\n        int idx = rng.next_int(0, cand-1);\n        int si = v[idx].second;\n        if (!used[si]) { used[si] = 1; out.push_back(si); }\n    }\n    return out;\n}\n\nstatic Point routeMedianCenter(const CurState& st) {\n    static array<int,100> xs, ys;\n    for (int i = 0; i < 100; i++) { xs[i] = st.pts[i+1].x; ys[i] = st.pts[i+1].y; }\n    nth_element(xs.begin(), xs.begin() + 50, xs.end());\n    nth_element(ys.begin(), ys.begin() + 50, ys.end());\n    return Point{xs[50], ys[50]};\n}\n\nstatic int sampleFromPoolCDF(const vector<int>& pool, const vector<double>& cdf,\n                             const array<uint8_t,1000>& forbidden, RNG& rng, int tries=220) {\n    double sum = cdf.back();\n    for (int t = 0; t < tries; t++) {\n        double r = rng.next_double() * sum;\n        int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n        idx = max(0, min(idx, (int)pool.size() - 1));\n        int id = pool[idx];\n        if (!forbidden[id]) return id;\n    }\n    return -1;\n}\n\nstatic int sampleFromPoolCDFNear(const vector<int>& pool, const vector<double>& cdf,\n                                 const array<uint8_t,1000>& forbidden, RNG& rng,\n                                 const Point& center, int radius,\n                                 const array<Point,1000>& pickPt, const array<Point,1000>& delPt,\n                                 int tries=300) {\n    double sum = cdf.back();\n    for (int t = 0; t < tries; t++) {\n        double r = rng.next_double() * sum;\n        int idx = (int)(lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin());\n        idx = max(0, min(idx, (int)pool.size() - 1));\n        int id = pool[idx];\n        if (forbidden[id]) continue;\n        if (max(distMan(center, pickPt[id]), distMan(center, delPt[id])) <= radius) return id;\n    }\n    return -1;\n}\n\nstatic array<int,50> sampleSelBiased(const vector<int>& pool, RNG& rng, const vector<double>& cdf) {\n    array<int,50> sel;\n    array<uint8_t,1000> used{}; used.fill(0);\n    for (int k = 0; k < 50; k++) {\n        int id = sampleFromPoolCDF(pool, cdf, used, rng);\n        if (id < 0) {\n            do { id = pool[rng.next_int(0, (int)pool.size()-1)]; } while (used[id]);\n        }\n        used[id] = 1;\n        sel[k] = id;\n    }\n    return sel;\n}\n\nstatic array<int,50> sampleSelCluster(const array<Point,1000>& pickPt,\n                                      const array<Point,1000>& delPt,\n                                      RNG& rng,\n                                      const Point& center) {\n    vector<pair<int,int>> v;\n    v.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int cp = distMan(center, pickPt[i]);\n        int cd = distMan(center, delPt[i]);\n        int pd = distMan(pickPt[i], delPt[i]);\n        int op = distMan(OFFICE, pickPt[i]);\n        int od = distMan(OFFICE, delPt[i]);\n        int score = (cp + cd) * 100 + pd * 28 + (op + od) * 10;\n        v.push_back({score, i});\n    }\n    nth_element(v.begin(), v.begin() + 50, v.end());\n    v.resize(50);\n    array<int,50> sel;\n    for (int i = 0; i < 50; i++) sel[i] = v[i].second;\n    return sel;\n}\n\nstatic inline void shuffleVec(vector<int>& a, RNG& rng) {\n    for (int i = (int)a.size() - 1; i > 0; i--) {\n        int j = rng.next_int(0, i);\n        swap(a[i], a[j]);\n    }\n}\n\nstatic pair<array<Node,100>, int> buildCheapestInsertionRoute(const array<int,50>& sel,\n                                                              vector<int> orderIds,\n                                                              const array<Point,1000>& pickPt,\n                                                              const array<Point,1000>& delPt) {\n    Seq nodes;\n    int cost = 0;\n    for (int id : orderIds) {\n        auto res = bestInsertPairFixed(nodes, pickPt[id], delPt[id], id, pickPt, delPt);\n        nodes = res.first;\n        cost = res.second;\n    }\n    array<Node,100> seq;\n    for (int i = 0; i < 100; i++) seq[i] = nodes.a[i];\n    return {seq, cost};\n}\n\nstatic CurState buildStateFromSelTryConstructors(const array<int,50>& sel,\n                                                const array<Point,1000>& pickPt,\n                                                const array<Point,1000>& delPt,\n                                                RNG& rng) {\n    CurState st;\n    st.sel = sel;\n    st.selected.fill(0);\n    for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n\n    // A: greedy interleaving\n    array<Node,100> bestSeq = buildGreedyInterleaving(pickPt, delPt, st.sel);\n    CurState tmp;\n    tmp.sel = st.sel; tmp.seq = bestSeq; tmp.selected = st.selected;\n    buildPtsAndPos(tmp, pickPt, delPt);\n    int bestCost = tmp.cost;\n\n    // B: cheapest insertion far-first\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            int da = distMan(OFFICE, pickPt[a]) + distMan(OFFICE, delPt[a]);\n            int db = distMan(OFFICE, pickPt[b]) + distMan(OFFICE, delPt[b]);\n            return da > db;\n        });\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n    // C: cheapest insertion random\n    {\n        vector<int> ids(50);\n        for (int i = 0; i < 50; i++) ids[i] = sel[i];\n        shuffleVec(ids, rng);\n        auto [seq2, cost2] = buildCheapestInsertionRoute(sel, ids, pickPt, delPt);\n        if (cost2 < bestCost) { bestCost = cost2; bestSeq = seq2; }\n    }\n\n    st.seq = bestSeq;\n    buildPtsAndPos(st, pickPt, delPt);\n    return st;\n}\n\n// ----------------- LNS moves -----------------\nstatic bool moveRouteLNSk(CurState& cur,\n                          const array<Point,1000>& pickPt,\n                          const array<Point,1000>& delPt,\n                          RNG& rng,\n                          int k,\n                          double temp,\n                          int postImproveIters) {\n    auto outIdx = pickKOutIndices(cur, rng, k);\n    vector<int> outIds; outIds.reserve(k);\n    vector<int> skipPos; skipPos.reserve(2*k);\n\n    for (int t = 0; t < k; t++) {\n        int si = outIdx[t];\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 2*k) return false;\n\n    Seq base = buildBaseFromSkip(cur.seq, skipPos);\n    auto [bestNodes, newCost] = bestPermutationInsertKFixed(base, outIds, pickPt, delPt);\n\n    int delta = newCost - cur.cost;\n    if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) return false;\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = bestNodes.a[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    if (postImproveIters > 0) greedyImproveRelocate(cur, pickPt, delPt, rng, postImproveIters);\n    return true;\n}\n\nstatic bool moveSelectionLNS3(CurState& cur,\n                              const vector<int>& pool,\n                              const vector<double>& cdf,\n                              const array<Point,1000>& pickPt,\n                              const array<Point,1000>& delPt,\n                              RNG& rng,\n                              double temp,\n                              int postImproveIters) {\n    auto outIdx = pickKOutIndices(cur, rng, 3);\n    vector<int> outIds; outIds.reserve(3);\n    vector<int> skipPos; skipPos.reserve(6);\n\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int id = cur.sel[si];\n        outIds.push_back(id);\n        int p = cur.pickPos[id], d = cur.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 6) return false;\n\n    Point center = routeMedianCenter(cur);\n\n    array<uint8_t,1000> forbidden = cur.selected;\n    vector<int> inIds; inIds.reserve(3);\n\n    int id0 = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n    if (id0 < 0) return false;\n    forbidden[id0] = 1;\n    inIds.push_back(id0);\n\n    for (int t = 0; t < 2; t++) {\n        int id = -1;\n        if (rng.next_double() < 0.75)\n            id = sampleFromPoolCDFNear(pool, cdf, forbidden, rng, center, 360, pickPt, delPt);\n        if (id < 0) id = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n        if (id < 0) return false;\n        forbidden[id] = 1;\n        inIds.push_back(id);\n    }\n\n    Seq base = buildBaseFromSkip(cur.seq, skipPos);\n    auto [bestNodes, newCost] = bestPermutationInsertKFixed(base, inIds, pickPt, delPt);\n\n    int delta = newCost - cur.cost;\n    if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) return false;\n\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int outId = outIds[t];\n        int inId = inIds[t];\n        cur.selected[outId] = 0;\n        cur.selected[inId] = 1;\n        cur.sel[si] = inId;\n    }\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = bestNodes.a[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n    if (postImproveIters > 0) greedyImproveRelocate(cur, pickPt, delPt, rng, postImproveIters);\n    return true;\n}\n\nstatic bool tryImproveRouteLNSk(CurState& st,\n                                const array<Point,1000>& pickPt,\n                                const array<Point,1000>& delPt,\n                                RNG& rng,\n                                int k,\n                                int tries) {\n    bool improved = false;\n    for (int t = 0; t < tries; t++) {\n        CurState bak = st;\n        if (!moveRouteLNSk(st, pickPt, delPt, rng, k, /*temp*/1e-12, /*post*/0)) { st = bak; continue; }\n        if (st.cost < bak.cost) improved = true;\n        else st = bak;\n    }\n    return improved;\n}\n\n// Best-of-K single selection swap (supports greedy-only mode)\nstatic bool moveSelectionSwapBestOfK(CurState& cur,\n                                     const vector<int>& pool,\n                                     const vector<double>& cdf,\n                                     const array<Point,1000>& pickPt,\n                                     const array<Point,1000>& delPt,\n                                     RNG& rng,\n                                     double temp,\n                                     int K,\n                                     bool greedyOnly) {\n    (void)cdf; // sampling uses CDF through sampleFromPoolCDF*; keep for signature symmetry\n    int outIdx = (rng.next_double() < 0.80) ? pickOutIdxBiased(cur, rng) : rng.next_int(0, 49);\n    int outId = cur.sel[outIdx];\n\n    int pi = cur.pickPos[outId], di = cur.delPos[outId];\n    if (!(0 <= pi && pi < di && di < 100)) return false;\n\n    vector<int> skip = {pi, di};\n    sort(skip.begin(), skip.end());\n    Seq base = buildBaseFromSkip(cur.seq, skip);\n\n    Point center = routeMedianCenter(cur);\n\n    array<uint8_t,1000> forbidden = cur.selected;\n    forbidden[outId] = 1;\n    array<uint8_t,1000> tried{}; tried.fill(0);\n\n    int bestIn = -1;\n    int bestCost = INT_MAX;\n    Seq bestSeq;\n\n    for (int t = 0; t < K; t++) {\n        int inId = -1;\n        if (rng.next_double() < 0.70) {\n            inId = sampleFromPoolCDFNear(pool, cdf, forbidden, rng, center, 340, pickPt, delPt);\n        }\n        if (inId < 0) inId = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n        if (inId < 0) break;\n        if (tried[inId]) continue;\n        tried[inId] = 1;\n\n        auto [ns, nc] = bestInsertPairFixed(base, pickPt[inId], delPt[inId], inId, pickPt, delPt);\n        if (nc < bestCost) {\n            bestCost = nc;\n            bestIn = inId;\n            bestSeq = ns;\n        }\n    }\n    if (bestIn < 0) return false;\n\n    int delta = bestCost - cur.cost;\n    if (greedyOnly) {\n        if (delta >= 0) return false;\n    } else {\n        if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) return false;\n    }\n\n    cur.selected[outId] = 0;\n    cur.selected[bestIn] = 1;\n    cur.sel[outIdx] = bestIn;\n\n    for (int i = 0; i < 100; i++) cur.seq[i] = bestSeq.a[i];\n    buildPtsAndPos(cur, pickPt, delPt);\n\n    greedyImproveRelocate(cur, pickPt, delPt, rng, 180);\n    return true;\n}\n\n// Greedy selection LNS3: best-of-M candidate triplets, accept only if improved\nstatic bool greedySelectionLNS3_bestOfM(CurState& st,\n                                       const vector<int>& pool,\n                                       const vector<double>& cdf,\n                                       const array<Point,1000>& pickPt,\n                                       const array<Point,1000>& delPt,\n                                       RNG& rng,\n                                       int M) {\n    auto outIdx = pickKOutIndices(st, rng, 3);\n    vector<int> outIds; outIds.reserve(3);\n    vector<int> skipPos; skipPos.reserve(6);\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int id = st.sel[si];\n        outIds.push_back(id);\n        int p = st.pickPos[id], d = st.delPos[id];\n        if (!(0 <= p && p < d && d < 100)) return false;\n        skipPos.push_back(p);\n        skipPos.push_back(d);\n    }\n    sort(skipPos.begin(), skipPos.end());\n    skipPos.erase(unique(skipPos.begin(), skipPos.end()), skipPos.end());\n    if ((int)skipPos.size() != 6) return false;\n\n    Seq base = buildBaseFromSkip(st.seq, skipPos);\n    Point center = routeMedianCenter(st);\n\n    int bestCost = st.cost;\n    Seq bestNodes;\n    vector<int> bestInIds;\n\n    for (int trial = 0; trial < M; trial++) {\n        array<uint8_t,1000> forbidden = st.selected;\n        for (int id : outIds) forbidden[id] = 1; // don't re-add removed ones\n\n        vector<int> inIds;\n        inIds.reserve(3);\n\n        int id0 = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n        if (id0 < 0) continue;\n        forbidden[id0] = 1;\n        inIds.push_back(id0);\n\n        for (int t = 0; t < 2; t++) {\n            int id = -1;\n            if (rng.next_double() < 0.75)\n                id = sampleFromPoolCDFNear(pool, cdf, forbidden, rng, center, 360, pickPt, delPt);\n            if (id < 0) id = sampleFromPoolCDF(pool, cdf, forbidden, rng);\n            if (id < 0) { inIds.clear(); break; }\n            forbidden[id] = 1;\n            inIds.push_back(id);\n        }\n        if ((int)inIds.size() != 3) continue;\n\n        auto [nodes, cost] = bestPermutationInsertKFixed(base, inIds, pickPt, delPt);\n        if (cost < bestCost) {\n            bestCost = cost;\n            bestNodes = nodes;\n            bestInIds = inIds;\n        }\n    }\n\n    if (bestCost >= st.cost) return false;\n\n    // apply\n    for (int t = 0; t < 3; t++) {\n        int si = outIdx[t];\n        int outId = outIds[t];\n        int inId = bestInIds[t];\n        st.selected[outId] = 0;\n        st.selected[inId] = 1;\n        st.sel[si] = inId;\n    }\n    for (int i = 0; i < 100; i++) st.seq[i] = bestNodes.a[i];\n    buildPtsAndPos(st, pickPt, delPt);\n\n    greedyImproveRelocate(st, pickPt, delPt, rng, 200);\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<Order> ord(1000);\n    for (int i = 0; i < 1000; i++) cin >> ord[i].ax >> ord[i].ay >> ord[i].cx >> ord[i].cy;\n\n    array<Point,1000> pickPt, delPt;\n    for (int i = 0; i < 1000; i++) {\n        pickPt[i] = Point{ord[i].ax, ord[i].ay};\n        delPt[i]  = Point{ord[i].cx, ord[i].cy};\n    }\n\n    // deterministic seed from input hash\n    uint64_t h = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) { h ^= v; h *= 1099511628211ULL; };\n    for (int i = 0; i < 1000; i++) {\n        mix((uint64_t)ord[i].ax); mix((uint64_t)ord[i].ay);\n        mix((uint64_t)ord[i].cx); mix((uint64_t)ord[i].cy);\n    }\n    RNG rng(h ^ 0x9e3779b97f4a7c15ULL);\n\n    // pool by solo cost\n    vector<pair<int,int>> solo;\n    solo.reserve(1000);\n    for (int i = 0; i < 1000; i++) {\n        int c = distMan(OFFICE, pickPt[i]) + distMan(pickPt[i], delPt[i]) + distMan(delPt[i], OFFICE);\n        solo.push_back({c, i});\n    }\n    sort(solo.begin(), solo.end());\n\n    // full pool, but biased CDF by rank\n    vector<int> pool; pool.reserve(1000);\n    for (int i = 0; i < 1000; i++) pool.push_back(solo[i].second);\n\n    const double alpha = 1.13;\n    vector<double> cdf(pool.size());\n    double acc = 0.0;\n    for (int i = 0; i < (int)pool.size(); i++) {\n        double w = 1.0 / pow((double)(i + 1), alpha);\n        acc += w;\n        cdf[i] = acc;\n    }\n\n    auto t0 = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - t0).count();\n    };\n\n    const double INIT_LIMIT = 0.27;\n    const double SA_LIMIT   = 1.92;\n    const double DEADLINE   = 1.985;\n\n    // Initialization (multi-start)\n    BestState initBest;\n    {\n        array<int,50> sel0;\n        for (int i = 0; i < 50; i++) sel0[i] = solo[i].second;\n        CurState st = buildStateFromSelTryConstructors(sel0, pickPt, delPt, rng);\n        greedyImproveRelocate(st, pickPt, delPt, rng, 2000);\n        hillClimbOrderReinsert(st, pickPt, delPt, rng, 16);\n        initBest.cost = st.cost;\n        initBest.sel = st.sel;\n        initBest.seq = st.seq;\n\n        int restarts = 0;\n        while (elapsedSec() < INIT_LIMIT && restarts < 16) {\n            array<int,50> sel;\n            if (restarts < 10) {\n                sel = sampleSelBiased(pool, rng, cdf);\n            } else {\n                int baseId = rng.next_int(0, 999);\n                Point center = (rng.next_int(0, 1) ? pickPt[baseId] : delPt[baseId]);\n                if (rng.next_double() < 0.40) {\n                    Point corner{ (rng.next_int(0,1)?0:800), (rng.next_int(0,1)?0:800) };\n                    center.x = (center.x + corner.x) / 2;\n                    center.y = (center.y + corner.y) / 2;\n                }\n                sel = sampleSelCluster(pickPt, delPt, rng, center);\n            }\n\n            CurState st2 = buildStateFromSelTryConstructors(sel, pickPt, delPt, rng);\n            greedyImproveRelocate(st2, pickPt, delPt, rng, 1400);\n            hillClimbOrderReinsert(st2, pickPt, delPt, rng, 16);\n\n            if (st2.cost < initBest.cost) {\n                initBest.cost = st2.cost;\n                initBest.sel = st2.sel;\n                initBest.seq = st2.seq;\n            }\n            restarts++;\n        }\n    }\n\n    CurState cur;\n    cur.sel = initBest.sel;\n    cur.seq = initBest.seq;\n    cur.selected.fill(0);\n    for (int i = 0; i < 50; i++) cur.selected[cur.sel[i]] = 1;\n    buildPtsAndPos(cur, pickPt, delPt);\n\n    BestState best;\n    best.cost = cur.cost;\n    best.sel = cur.sel;\n    best.seq = cur.seq;\n\n    // SA schedule\n    const double T0 = 3000.0;\n    const double T1 = 12.0;\n\n    while (elapsedSec() < SA_LIMIT) {\n        double e = elapsedSec();\n        double prog = e / SA_LIMIT;\n        double temp = T0 * pow(T1 / T0, prog);\n\n        double r = rng.next_double();\n\n        if (r < 0.46) {\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (!canRelocateOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaRelocatePts(cur.pts, i, j);\n            if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) continue;\n\n            applyRelocate(cur.seq, i, j);\n            int l = min(i, j), rr = max(i, j);\n            updateRangeAfterRelocate(cur, pickPt, delPt, l, rr);\n            cur.cost += delta;\n\n        } else if (r < 0.58) {\n            int i = rng.next_int(0, 99);\n            int j = rng.next_int(0, 99);\n            if (i == j) continue;\n            if (i > j) swap(i, j);\n            if (!canSwapOrderConstraint(cur, i, j)) continue;\n\n            int delta = deltaSwapPts(cur.pts, i, j);\n            if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) continue;\n\n            swap(cur.seq[i], cur.seq[j]);\n            swap(cur.pts[i+1], cur.pts[j+1]);\n            updateAfterSwap(cur, pickPt, delPt, i, j);\n            cur.cost += delta;\n\n        } else if (r < 0.70) {\n            int idx = rng.next_int(0, 49);\n            int id = cur.sel[idx];\n            int pi = cur.pickPos[id], di = cur.delPos[id];\n            if (!(0 <= pi && pi < di && di < 100)) continue;\n\n            vector<int> skip = {pi, di};\n            sort(skip.begin(), skip.end());\n            Seq base = buildBaseFromSkip(cur.seq, skip);\n            auto [newSeq, newCost] = bestInsertPairFixed(base, pickPt[id], delPt[id], id, pickPt, delPt);\n\n            int delta = newCost - cur.cost;\n            if (delta > 0 && rng.next_double() >= exp(-(double)delta / temp)) continue;\n\n            for (int i = 0; i < 100; i++) cur.seq[i] = newSeq.a[i];\n            buildPtsAndPos(cur, pickPt, delPt);\n\n        } else if (r < 0.78) {\n            if (elapsedSec() < SA_LIMIT - 0.05) moveRouteLNSk(cur, pickPt, delPt, rng, 2, temp, 80);\n\n        } else if (r < 0.86) {\n            if (elapsedSec() < SA_LIMIT - 0.06) moveRouteLNSk(cur, pickPt, delPt, rng, 3, temp, 120);\n\n        } else if (r < 0.89) {\n            if (elapsedSec() < SA_LIMIT - 0.10) moveRouteLNSk(cur, pickPt, delPt, rng, 4, temp, 140);\n\n        } else if (r < 0.95) {\n            // K increased to 10 in SA\n            moveSelectionSwapBestOfK(cur, pool, cdf, pickPt, delPt, rng, temp, /*K=*/10, /*greedyOnly=*/false);\n\n        } else {\n            if (elapsedSec() < SA_LIMIT - 0.10) moveSelectionLNS3(cur, pool, cdf, pickPt, delPt, rng, temp, 140);\n        }\n\n        if (cur.cost < best.cost) {\n            best.cost = cur.cost;\n            best.sel = cur.sel;\n            best.seq = cur.seq;\n        }\n    }\n\n    // Final polish (improvement-only)\n    {\n        CurState st;\n        st.sel = best.sel;\n        st.seq = best.seq;\n        st.selected.fill(0);\n        for (int i = 0; i < 50; i++) st.selected[st.sel[i]] = 1;\n        buildPtsAndPos(st, pickPt, delPt);\n\n        // Greedy selection polishing\n        for (int t = 0; t < 10 && elapsedSec() < DEADLINE - 0.12; t++) {\n            bool ok = moveSelectionSwapBestOfK(st, pool, cdf, pickPt, delPt, rng,\n                                              /*temp*/0.0, /*K=*/18, /*greedyOnly=*/true);\n            if (!ok) break;\n        }\n        // Greedy selection LNS3 best-of-M (new)\n        for (int t = 0; t < 2 && elapsedSec() < DEADLINE - 0.12; t++) {\n            bool ok = greedySelectionLNS3_bestOfM(st, pool, cdf, pickPt, delPt, rng, /*M=*/3);\n            if (!ok) break;\n        }\n\n        tryImproveRouteLNSk(st, pickPt, delPt, rng, 2, 6);\n        tryImproveRouteLNSk(st, pickPt, delPt, rng, 3, 4);\n        if (elapsedSec() < DEADLINE - 0.06) tryImproveRouteLNSk(st, pickPt, delPt, rng, 4, 2);\n\n        while (elapsedSec() < DEADLINE) {\n            int before = st.cost;\n            hillClimbOrderReinsert(st, pickPt, delPt, rng, 22);\n            greedyImproveRelocate(st, pickPt, delPt, rng, 900);\n            if (st.cost < best.cost) {\n                best.cost = st.cost;\n                best.sel = st.sel;\n                best.seq = st.seq;\n            }\n            if (st.cost >= before) break;\n        }\n    }\n\n    // Output\n    cout << 50;\n    for (int i = 0; i < 50; i++) cout << \" \" << (best.sel[i] + 1);\n    cout << \"\\n\";\n\n    vector<Point> path;\n    path.reserve(102);\n    path.push_back(OFFICE);\n    for (int i = 0; i < 100; i++) path.push_back(nodePoint(pickPt, delPt, best.seq[i]));\n    path.push_back(OFFICE);\n\n    vector<Point> comp;\n    comp.reserve(path.size());\n    for (auto &p : path) {\n        if (comp.empty() || comp.back().x != p.x || comp.back().y != p.y) comp.push_back(p);\n    }\n\n    cout << (int)comp.size();\n    for (auto &p : comp) cout << \" \" << p.x << \" \" << p.y;\n    cout << \"\\n\";\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\n#include <atcoder/all>\n\nusing namespace std;\nusing atcoder::dsu;\n\nstatic inline int rounded_dist(int x1,int y1,int x2,int y2){\n    long long dx = x1 - x2;\n    long long dy = y1 - y2;\n    double dist = std::sqrt((double)dx*dx + (double)dy*dy);\n    return (int)llround(dist);\n}\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// DSU for contracted components\nstruct DSUFast {\n    int n;\n    vector<int> p, sz;\n    DSUFast(int n=0){ init(n); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int a){\n        while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; }\n        return a;\n    }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a;\n        sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// keep up to LIM smallest values, sorted\ntemplate<int LIM>\nstruct SmallK {\n    int sz = 0;\n    array<int, LIM> a;\n    void clear(){ sz = 0; }\n    void add(int v){\n        if(sz < LIM){\n            a[sz++] = v;\n            int j = sz-1;\n            while(j>0 && a[j] < a[j-1]) { swap(a[j], a[j-1]); --j; }\n        }else{\n            if(v >= a[LIM-1]) return;\n            a[LIM-1] = v;\n            int j = LIM-1;\n            while(j>0 && a[j] < a[j-1]) { swap(a[j], a[j-1]); --j; }\n        }\n    }\n};\n\n// expected value of min of uniforms X_i ~ U[d_i, 3 d_i] (continuous model)\nstatic long double expected_min_uniform_scaled(const int *d, int m){\n    if(m <= 0) return 1e30L;\n    // breakpoints: 0, all d_i, all 3 d_i\n    vector<long double> pts;\n    pts.reserve(2*m + 1);\n    pts.push_back(0.0L);\n    long double max3 = 0;\n    for(int i=0;i<m;i++){\n        long double di = (long double)d[i];\n        pts.push_back(di);\n        pts.push_back(3.0L*di);\n        max3 = max(max3, 3.0L*di);\n    }\n    sort(pts.begin(), pts.end());\n    pts.erase(unique(pts.begin(), pts.end()), pts.end());\n    if(pts.back() < max3) pts.push_back(max3);\n\n    long double res = 0.0L;\n\n    for(int pi=0; pi+1<(int)pts.size(); pi++){\n        long double L = pts[pi], R = pts[pi+1];\n        if(R <= L) continue;\n        // build polynomial for prod S_i(t) on this interval\n        // S_i(t) = 1 (t<d_i), linear (d_i<=t<=3d_i), 0 (t>3d_i).\n        vector<long double> poly(1, 1.0L); // degree 0 => 1\n        bool zero = false;\n        for(int i=0;i<m;i++){\n            long double di = (long double)d[i];\n            if(L >= 3.0L*di){\n                zero = true;\n                break;\n            }\n            long double a = 0.0L, b = 1.0L;\n            if(R <= di){\n                // constant 1\n                a = 0.0L; b = 1.0L;\n            }else{\n                // must be within [di,3di] because of breakpoints\n                // S(t)=(3di - t)/(2di) = (-1/(2di)) t + 3/2\n                a = -1.0L/(2.0L*di);\n                b = 1.5L;\n            }\n            if(a == 0.0L && b == 1.0L) continue;\n            vector<long double> np(poly.size()+1, 0.0L);\n            for(int k=0;k<(int)poly.size();k++){\n                np[k]   += poly[k] * b;\n                np[k+1] += poly[k] * a;\n            }\n            poly.swap(np);\n        }\n        if(zero) continue;\n\n        // integrate polynomial over [L,R]\n        // poly[k] * t^k\n        int deg = (int)poly.size()-1;\n        vector<long double> powL(deg+2, 1.0L), powR(deg+2, 1.0L);\n        for(int k=1;k<=deg+1;k++){\n            powL[k] = powL[k-1] * L;\n            powR[k] = powR[k-1] * R;\n        }\n        long double integ = 0.0L;\n        for(int k=0;k<=deg;k++){\n            long double coef = poly[k];\n            long double term = (powR[k+1] - powL[k+1]) / (long double)(k+1);\n            integ += coef * term;\n        }\n        res += integ;\n    }\n    return res;\n}\n\n// HLD for max query on path (edge values stored at child node position)\nint op_max(int a,int b){ return max(a,b); }\nint e_max(){ return 0; }\n\nstruct HLD {\n    int n;\n    vector<int> parent, depth, heavy, head, pos, sz;\n    vector<int> parEdgeD;\n    vector<int> parEdgeIdx;\n    int cur;\n\n    void build_from_tree(const vector<vector<tuple<int,int,int>>>& tree, int root=0) {\n        n = (int)tree.size();\n        parent.assign(n, -1);\n        depth.assign(n, 0);\n        heavy.assign(n, -1);\n        head.assign(n, 0);\n        pos.assign(n, 0);\n        sz.assign(n, 0);\n        parEdgeD.assign(n, 0);\n        parEdgeIdx.assign(n, -1);\n\n        vector<int> st = {root};\n        vector<int> order;\n        order.reserve(n);\n        while(!st.empty()){\n            int v = st.back(); st.pop_back();\n            order.push_back(v);\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v]) continue;\n                parent[to] = v;\n                depth[to] = depth[v] + 1;\n                parEdgeD[to] = d;\n                parEdgeIdx[to] = idx;\n                st.push_back(to);\n            }\n        }\n\n        for(int i=(int)order.size()-1;i>=0;--i){\n            int v = order[i];\n            sz[v] = 1;\n            int best=-1, bestSz=0;\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v]) continue;\n                sz[v] += sz[to];\n                if(sz[to] > bestSz){\n                    bestSz = sz[to];\n                    best = to;\n                }\n            }\n            heavy[v] = best;\n        }\n\n        cur = 0;\n        function<void(int,int)> decomp = [&](int v,int h){\n            head[v] = h;\n            pos[v] = cur++;\n            if(heavy[v] != -1) decomp(heavy[v], h);\n            for(auto [to, d, idx] : tree[v]){\n                if(to == parent[v] || to == heavy[v]) continue;\n                decomp(to, to);\n            }\n        };\n        decomp(root, root);\n    }\n\n    template<class Seg>\n    int query_max(int a, int b, Seg &seg) const {\n        int res = 0;\n        int u=a, v=b;\n        while(head[u] != head[v]){\n            if(depth[head[u]] < depth[head[v]]) swap(u,v);\n            res = max(res, seg.prod(pos[head[u]], pos[u] + 1));\n            u = parent[head[u]];\n        }\n        if(depth[u] > depth[v]) swap(u,v);\n        res = max(res, seg.prod(pos[u] + 1, pos[v] + 1)); // exclude LCA node position\n        return res;\n    }\n};\n\nstatic inline double clamp13(double x){\n    if(x < 1.0) return 1.0;\n    if(x > 3.0) return 3.0;\n    return x;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    const int N = 400;\n    const int M = 1995;\n\n    vector<int> x(N), y(N);\n    for(int i=0;i<N;i++){\n        if(!(cin >> x[i] >> y[i])) return 0;\n    }\n    vector<int> U(M), V(M);\n    for(int i=0;i<M;i++) cin >> U[i] >> V[i];\n\n    vector<int> D(M);\n    for(int i=0;i<M;i++){\n        D[i] = rounded_dist(x[U[i]], y[U[i]], x[V[i]], y[V[i]]);\n        if(D[i] <= 0) D[i] = 1;\n    }\n\n    // global D quantiles (very mild bias)\n    vector<int> Ds = D;\n    nth_element(Ds.begin(), Ds.begin() + M/5, Ds.end());\n    int d20 = Ds[M/5];\n    nth_element(Ds.begin(), Ds.begin() + (4*M)/5, Ds.end());\n    int d80 = Ds[(4*M)/5];\n\n    // Guide MSTs\n    const int K = 11;\n    vector<HLD> hld(K);\n    vector<atcoder::segtree<int, op_max, e_max>> segs;\n    segs.reserve(K);\n    vector<vector<int>> idxToChild(K, vector<int>(M, -1));\n    vector<int> membershipCnt(M, 0);\n    vector<char> inMST0(M, false);\n\n    for(int k=0;k<K;k++){\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a,int b){\n            if(D[a] != D[b]) return D[a] < D[b];\n            if(k==0){\n                if(U[a] != U[b]) return U[a] < U[b];\n                if(V[a] != V[b]) return V[a] < V[b];\n                return a < b;\n            }else{\n                uint64_t ha = splitmix64((uint64_t)a ^ (uint64_t)k * 0x9e3779b97f4a7c15ULL);\n                uint64_t hb = splitmix64((uint64_t)b ^ (uint64_t)k * 0x9e3779b97f4a7c15ULL);\n                if(ha != hb) return ha < hb;\n                return a < b;\n            }\n        });\n\n        dsu uf(N);\n        vector<vector<tuple<int,int,int>>> tree(N);\n        int picked=0;\n        for(int idx: ord){\n            if(picked == N-1) break;\n            int a=U[idx], b=V[idx];\n            if(uf.same(a,b)) continue;\n            uf.merge(a,b);\n            picked++;\n            tree[a].push_back({b, D[idx], idx});\n            tree[b].push_back({a, D[idx], idx});\n            membershipCnt[idx]++;\n            if(k==0) inMST0[idx] = true;\n        }\n\n        hld[k].build_from_tree(tree, 0);\n\n        for(int v=1; v<N; v++){\n            int idx = hld[k].parEdgeIdx[v];\n            if(idx >= 0) idxToChild[k][idx] = v;\n        }\n\n        vector<int> init(N, 0);\n        for(int v=1; v<N; v++){\n            init[hld[k].pos[v]] = hld[k].parEdgeD[v];\n        }\n        segs.emplace_back(init);\n    }\n\n    dsu ufAcc(N);\n    int comps = N;\n    vector<int> leaderV(N), idOfLeader(N, -1);\n\n    for(int i=0;i<M;i++){\n        int l;\n        if(!(cin >> l)) break;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        if(comps == 1 || ufAcc.same(u,v)){\n            ans = 0;\n        } else {\n            // component mapping\n            fill(idOfLeader.begin(), idOfLeader.end(), -1);\n            int C = 0;\n            for(int vv=0; vv<N; vv++){\n                leaderV[vv] = ufAcc.leader(vv);\n                int &id = idOfLeader[leaderV[vv]];\n                if(id == -1) id = C++;\n            }\n            int cu = idOfLeader[leaderV[u]];\n            int cv = idOfLeader[leaderV[v]];\n\n            // suffix scan: connectivity + alternatives (keep small sets)\n            DSUFast tmp(C);\n            int cc = C;\n\n            SmallK<8> between, outCu, outCv;\n            between.clear(); outCu.clear(); outCv.clear();\n            int cntBetween = 0, cntOutCu = 0, cntOutCv = 0;\n\n            for(int j=i+1;j<M;j++){\n                int a = idOfLeader[ leaderV[U[j]] ];\n                int b = idOfLeader[ leaderV[V[j]] ];\n                if(a==b) continue;\n\n                if(tmp.unite(a,b)) cc--;\n\n                if((a==cu && b==cv) || (a==cv && b==cu)){\n                    if(cntBetween < 100) cntBetween++;\n                    between.add(D[j]);\n                }\n                if(a==cu || b==cu){\n                    if(cntOutCu < 100) cntOutCu++;\n                    outCu.add(D[j]);\n                }\n                if(a==cv || b==cv){\n                    if(cntOutCv < 100) cntOutCv++;\n                    outCv.add(D[j]);\n                }\n            }\n\n            bool okReject = (cc == 1);\n            bool take = false;\n\n            if(!okReject){\n                take = true; // forced\n            } else {\n                double t = (double)i / (double)(M-1);\n                double remain = max(1, (M-1-i));\n                double need = comps - 1;\n                double urg = min(1.0, need / remain);\n\n                double mult = 1.0 + 0.95 * pow(urg, 1.15);\n\n                double cheapK    = clamp13((1.35 + 0.35*t) * mult);\n                double replK     = clamp13((1.75 + 0.35*t) * mult);\n                double treeK     = clamp13((2.10 + 0.30*t) * mult);\n                double replSelfK = clamp13((1.55 + 0.30*t) * mult);\n\n                // mild D-quantile bias\n                if(D[i] <= d20){\n                    cheapK = clamp13(cheapK + 0.02);\n                    replSelfK = clamp13(replSelfK + 0.02);\n                } else if(D[i] >= d80){\n                    cheapK = clamp13(cheapK - 0.02);\n                    replSelfK = clamp13(replSelfK - 0.02);\n                }\n\n                int mc = membershipCnt[i]; // 0..K\n                double imp = (double)mc / (double)K; // 0..1\n\n                // smooth membership bias\n                double delta = 0.09 * (imp - 0.33); // approx [-0.03 .. +0.06]\n                cheapK    = clamp13(cheapK + 0.55*delta);\n                treeK     = clamp13(treeK  + 0.75*delta);\n                replSelfK = clamp13(replSelfK + 0.70*delta);\n                if(mc == 0){\n                    replK     = clamp13(replK - 0.06);\n                    replSelfK = clamp13(replSelfK - 0.04);\n                }\n\n                // if almost no future outgoing edges for a component, be a bit more willing\n                if(cntOutCu <= 1 || cntOutCv <= 1){\n                    cheapK = clamp13(cheapK + 0.03);\n                    treeK  = clamp13(treeK  + 0.02);\n                    replSelfK = clamp13(replSelfK + 0.02);\n                }\n\n                // compute expected best future direct/outgoing only when urgency is low\n                auto exp_best_from = [&](const SmallK<8>& sk)->long double{\n                    if(sk.sz == 0) return 1e30L;\n                    return expected_min_uniform_scaled(sk.a.data(), sk.sz);\n                };\n\n                if(urg < 0.45){\n                    // direct alternative between components\n                    if(cntBetween >= 2 && between.sz >= 2){\n                        long double expBetween = exp_best_from(between);\n                        // if current is clearly worse than expected best direct future option, tighten\n                        long double thr = expBetween * (1.10L + (long double)(0.06*(0.5-imp))); // a bit stricter for low imp\n                        if((long double)l > thr){\n                            cheapK = clamp13(cheapK - 0.03);\n                            replSelfK = clamp13(replSelfK - 0.03);\n                        }\n                    }\n                    // outgoing alternatives\n                    if(cntOutCu >= 3 && cntOutCv >= 3 && outCu.sz >= 2 && outCv.sz >= 2){\n                        long double expOut = min(exp_best_from(outCu), exp_best_from(outCv));\n                        if(expOut < 1e20L){\n                            if((long double)l > expOut * 1.28L){\n                                cheapK = clamp13(cheapK - 0.02);\n                                replSelfK = clamp13(replSelfK - 0.02);\n                            }\n                        }\n                    }\n                }\n\n                long long L = l;\n                long long di = D[i];\n\n                auto leq_di = [&](double k)->bool{\n                    return L * 1000LL <= di * (long long)llround(k * 1000.0);\n                };\n\n                // 1) primary guide MST edge\n                if(inMST0[i] && leq_di(treeK)) take = true;\n\n                // 2) cheap by itself\n                if(!take && leq_di(cheapK)) take = true;\n\n                // 3) replacement by guide bottleneck\n                if(!take){\n                    vector<int> md(K);\n                    for(int k=0;k<K;k++) md[k] = hld[k].query_max(u, v, segs[k]);\n                    sort(md.begin(), md.end());\n\n                    // quantile choice based on importance (avoid extremes too often)\n                    int q;\n                    if(mc == 0) q = 0;\n                    else if(mc == K) q = K-1;\n                    else {\n                        double qq = (0.10 + 0.80*imp) * (K-1);\n                        q = (int)llround(qq);\n                        q = max(0, min(K-1, q));\n                    }\n\n                    int mdUse = md[q];\n                    if(mdUse > 0){\n                        // adaptive geometry gate\n                        double gate = 1.14 + 0.24 * imp; // [1.14..1.38]\n                        if(di * 1000LL <= (long long)mdUse * (long long)llround(gate * 1000.0)){\n                            bool ok1 = (L * 1000LL <= (long long)mdUse * (long long)llround(replK * 1000.0));\n                            bool ok2 = (L * 1000LL <= di * (long long)llround(replSelfK * 1000.0));\n                            if(ok1 && ok2) take = true;\n                        }\n                    }\n                }\n            }\n\n            if(take){\n                ufAcc.merge(u,v);\n                comps--;\n                ans = 1;\n            } else {\n                ans = 0;\n            }\n        }\n\n        cout << ans << \"\\n\";\n        cout.flush();\n\n        // remove processed edges from guide trees\n        for(int k=0;k<K;k++){\n            int child = idxToChild[k][i];\n            if(child != -1){\n                segs[k].set(hld[k].pos[child], 0);\n            }\n        }\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 30, W = 30;\nstatic constexpr int INF = 1e9;\n\nstruct Pet { int x, y, t; };\nstruct Human { int x, y; };\nstruct Rect { int x1, x2, y1, y2; }; // inclusive\n\nstatic inline bool inb(int x,int y){ return 1<=x && x<=H && 1<=y && y<=W; }\nstatic inline int manhattan(int ax,int ay,int bx,int by){ return abs(ax-bx)+abs(ay-by); }\n\nstatic const int dx4[4] = {-1,+1,0,0};\nstatic const int dy4[4] = {0,0,-1,+1};\nstatic const char MOVE_CH[4]  = {'U','D','L','R'};\nstatic const char BUILD_CH[4] = {'u','d','l','r'};\n\nstruct DoorInfo {\n    int x=-1,y=-1;        // door cell (on wall line outside the rect)\n    int inx=-1, iny=-1;   // adjacent cell inside rect\n    long long score=LLONG_MIN;\n};\n\nstatic void bfs_dist(vector<vector<int>>& dist,\n                     const vector<pair<int,int>>& sources,\n                     const function<bool(int,int)>& passable){\n    dist.assign(H+1, vector<int>(W+1, INF));\n    deque<pair<int,int>> q;\n    for(auto [sx,sy]: sources){\n        if(!inb(sx,sy)) continue;\n        if(!passable(sx,sy)) continue;\n        dist[sx][sy]=0;\n        q.push_back({sx,sy});\n    }\n    while(!q.empty()){\n        auto [x,y]=q.front(); q.pop_front();\n        int nd = dist[x][y] + 1;\n        for(int d=0; d<4; d++){\n            int nx=x+dx4[d], ny=y+dy4[d];\n            if(!inb(nx,ny)) continue;\n            if(!passable(nx,ny)) continue;\n            if(dist[nx][ny] > nd){\n                dist[nx][ny]=nd;\n                q.push_back({nx,ny});\n            }\n        }\n    }\n}\n\nstatic char step_by_dist(int x,int y,\n                         const vector<vector<int>>& dist,\n                         const function<bool(int,int)>& passable,\n                         const function<int(int,int)>& tiePenalty){\n    int cur = dist[x][y];\n    int bestDir=-1, bestD=cur, bestPen=INF;\n    for(int d=0; d<4; d++){\n        int nx=x+dx4[d], ny=y+dy4[d];\n        if(!inb(nx,ny)) continue;\n        if(!passable(nx,ny)) continue;\n        int nd = dist[nx][ny];\n        if(nd < bestD){\n            bestD = nd;\n            bestPen = tiePenalty(nx,ny);\n            bestDir = d;\n        }else if(nd == bestD && bestDir!=-1){\n            int pen = tiePenalty(nx,ny);\n            if(pen < bestPen){\n                bestPen = pen;\n                bestDir = d;\n            }\n        }\n    }\n    if(bestDir==-1 || bestD>=cur) return '.';\n    return MOVE_CH[bestDir];\n}\n\nstatic inline int dist_point_to_rect(int x,int y, const Rect& r){\n    int dx=0, dy=0;\n    if(x < r.x1) dx = r.x1 - x;\n    else if(x > r.x2) dx = x - r.x2;\n    if(y < r.y1) dy = r.y1 - y;\n    else if(y > r.y2) dy = y - r.y2;\n    return dx+dy;\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N; cin >> N;\n    vector<Pet> pets(N);\n    for(int i=0;i<N;i++) cin >> pets[i].x >> pets[i].y >> pets[i].t;\n    int M; cin >> M;\n    vector<Human> humans(M);\n    for(int i=0;i<M;i++) cin >> humans[i].x >> humans[i].y;\n\n    auto inside = [&](const Rect& r, int x, int y)->bool{\n        return r.x1 <= x && x <= r.x2 && r.y1 <= y && y <= r.y2;\n    };\n\n    auto make_rect = [&](int corner, int h, int w)->Rect{\n        Rect r;\n        if(corner==0){ r.x1=1; r.x2=h; r.y1=1; r.y2=w; }                   // TL\n        if(corner==1){ r.x1=1; r.x2=h; r.y1=W-w+1; r.y2=W; }               // TR\n        if(corner==2){ r.x1=H-h+1; r.x2=H; r.y1=1; r.y2=w; }               // BL\n        if(corner==3){ r.x1=H-h+1; r.x2=H; r.y1=W-w+1; r.y2=W; }           // BR\n        return r;\n    };\n\n    auto wall_cells_for = [&](const Rect& r)->vector<pair<int,int>>{\n        vector<pair<int,int>> cells;\n        if(r.x1 > 1){\n            int x = r.x1 - 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.x2 < H){\n            int x = r.x2 + 1;\n            for(int y=r.y1;y<=r.y2;y++) cells.push_back({x,y});\n        }\n        if(r.y1 > 1){\n            int y = r.y1 - 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        if(r.y2 < W){\n            int y = r.y2 + 1;\n            for(int x=r.x1;x<=r.x2;x++) cells.push_back({x,y});\n        }\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        return cells;\n    };\n\n    auto count_pets_in_rect = [&](const Rect& r)->int{\n        int c=0;\n        for(auto &p: pets) if(inside(r,p.x,p.y)) c++;\n        return c;\n    };\n\n    auto dist_pet_to_rect = [&](const Rect& r)->int{\n        int best=INF;\n        for(auto &p: pets) best=min(best, dist_point_to_rect(p.x,p.y,r));\n        return best;\n    };\n\n    auto max_human_dist_to_rect = [&](const Rect& r)->int{\n        int mx=0;\n        for(auto &h: humans) mx=max(mx, dist_point_to_rect(h.x,h.y,r));\n        return mx;\n    };\n\n    auto wall_pet_bad_count = [&](const vector<pair<int,int>>& wallCells)->int{\n        int cnt=0;\n        for(auto [x,y]: wallCells){\n            int md=INF;\n            for(auto &p: pets) md=min(md, manhattan(x,y,p.x,p.y));\n            if(md<=1) cnt++;\n        }\n        return cnt;\n    };\n\n    auto choose_doors = [&](const Rect& r, const vector<pair<int,int>>& wallCells, int K)->vector<DoorInfo>{\n        static bool isWall[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) isWall[x][y]=false;\n        for(auto [x,y]: wallCells) isWall[x][y]=true;\n\n        vector<DoorInfo> cand;\n        cand.reserve(wallCells.size());\n        for(auto [wx,wy]: wallCells){\n            int inx=-1, iny=-1;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(inb(nx,ny) && inside(r,nx,ny)){ inx=nx; iny=ny; break; }\n            }\n            if(inx==-1) continue;\n\n            bool okOutside=false;\n            for(int d=0; d<4; d++){\n                int nx=wx+dx4[d], ny=wy+dy4[d];\n                if(!inb(nx,ny)) continue;\n                if(inside(r,nx,ny)) continue;\n                if(isWall[nx][ny]) continue;\n                okOutside=true;\n            }\n            if(!okOutside) continue;\n\n            int minPetDist=1000;\n            for(auto &p: pets) minPetDist=min(minPetDist, manhattan(wx,wy,p.x,p.y));\n            long long sumHumanDist=0;\n            for(auto &h: humans) sumHumanDist += manhattan(h.x,h.y,inx,iny);\n\n            int borderPenalty = (wx==1 || wx==H || wy==1 || wy==W) ? 50 : 0;\n\n            DoorInfo di;\n            di.x=wx; di.y=wy; di.inx=inx; di.iny=iny;\n            di.score = 280LL*minPetDist - 1LL*sumHumanDist - borderPenalty;\n            cand.push_back(di);\n        }\n        sort(cand.begin(), cand.end(), [&](const DoorInfo& a, const DoorInfo& b){\n            return a.score > b.score;\n        });\n\n        vector<DoorInfo> res;\n        for(auto &d: cand){\n            bool far=true;\n            for(auto &e: res) if(manhattan(d.x,d.y,e.x,e.y) < 5) { far=false; break; }\n            if(!far) continue;\n            res.push_back(d);\n            if((int)res.size()>=K) break;\n        }\n        for(auto &d: cand){\n            if((int)res.size()>=K) break;\n            bool used=false;\n            for(auto &e: res) if(e.x==d.x && e.y==d.y) used=true;\n            if(!used) res.push_back(d);\n        }\n        return res;\n    };\n\n    // ---- choose rectangle ----\n    Rect rect{1,6,1,6};\n    vector<DoorInfo> doors;\n    double bestEval=-1e100;\n    int builders = max(1, min(M, 8));\n\n    for(int corner=0; corner<4; corner++){\n        for(int h=5; h<=20; h++){\n            for(int w=5; w<=20; w++){\n                Rect r = make_rect(corner,h,w);\n                int area = (r.x2-r.x1+1)*(r.y2-r.y1+1);\n                auto wallCells = wall_cells_for(r);\n                int wallLen = (int)wallCells.size();\n                if(wallLen==0) continue;\n\n                // avoid initial occupancy on wall cells\n                bool bad=false;\n                for(auto [x,y]: wallCells){\n                    for(auto &p: pets) if(p.x==x && p.y==y) { bad=true; break; }\n                    if(bad) break;\n                    for(auto &hu: humans) if(hu.x==x && hu.y==y) { bad=true; break; }\n                    if(bad) break;\n                }\n                if(bad) continue;\n\n                int K = (wallLen >= 22 ? 2 : 1);\n                auto ds = choose_doors(r, wallCells, K);\n                if((int)ds.size() < K) continue;\n\n                int petsIn = count_pets_in_rect(r);\n                int minPet = dist_pet_to_rect(r);\n                int maxHum = max_human_dist_to_rect(r);\n                int badWall = wall_pet_bad_count(wallCells);\n                double buildTime = (double)wallLen / builders;\n\n                double val = (double)area / 900.0;\n                val *= pow(0.5, 3.0 * petsIn);\n                val *= (1.0 + 0.06 * minPet);\n                val *= exp(-0.05 * maxHum);\n                val *= exp(-0.11 * buildTime);\n                val *= exp(-0.55 * badWall);\n\n                if(val > bestEval){\n                    bestEval = val;\n                    rect = r;\n                    doors = ds;\n                }\n            }\n        }\n    }\n\n    if(doors.empty()){\n        rect = make_rect(0,8,8);\n        auto wallCells = wall_cells_for(rect);\n        doors = choose_doors(rect, wallCells, 1);\n        if(doors.empty()){\n            doors.push_back(DoorInfo{1,1,1,2,0});\n        }\n    }\n\n    auto wallCells = wall_cells_for(rect);\n\n    static bool blocked[H+1][W+1];\n    static bool targetWall[H+1][W+1];\n    for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n        blocked[x][y]=false;\n        targetWall[x][y]=false;\n    }\n    for(auto [x,y]: wallCells) targetWall[x][y]=true;\n    for(auto &d: doors) targetWall[d.x][d.y]=false; // doors left open until closing\n\n    auto insideRect = [&](int x,int y){ return inside(rect,x,y); };\n\n    // gather point: 2 steps inside from best door\n    pair<int,int> gather;\n    {\n        auto d0 = doors[0];\n        int gx=d0.inx, gy=d0.iny;\n        int vx=d0.inx-d0.x, vy=d0.iny-d0.y;\n        int gx2=gx+vx, gy2=gy+vy;\n        if(inb(gx2,gy2) && insideRect(gx2,gy2)){ gx=gx2; gy=gy2; }\n        gather = {gx,gy};\n    }\n\n    auto compute_occupancy = [&](vector<vector<bool>>& petAt, vector<vector<bool>>& humanAt){\n        petAt.assign(H+1, vector<bool>(W+1,false));\n        humanAt.assign(H+1, vector<bool>(W+1,false));\n        for(auto &p: pets) petAt[p.x][p.y]=true;\n        for(auto &h: humans) humanAt[h.x][h.y]=true;\n    };\n\n    auto canBuild = [&](int tx,int ty,\n                        const vector<vector<bool>>& petAt,\n                        const vector<vector<bool>>& humanAt)->bool{\n        if(!inb(tx,ty)) return false;\n        if(petAt[tx][ty] || humanAt[tx][ty]) return false;\n        for(int d=0; d<4; d++){\n            int nx=tx+dx4[d], ny=ty+dy4[d];\n            if(inb(nx,ny) && petAt[nx][ny]) return false;\n        }\n        return true;\n    };\n\n    mt19937 rng(0);\n\n    for(int turn=0; turn<300; turn++){\n        vector<vector<bool>> petAt, humanAt;\n        compute_occupancy(petAt, humanAt);\n\n        int remWalls=0;\n        for(auto [x,y]: wallCells){\n            if(targetWall[x][y] && !blocked[x][y]) remWalls++;\n        }\n\n        int insideCnt=0;\n        for(auto &h: humans) if(insideRect(h.x,h.y)) insideCnt++;\n        bool allInside = (insideCnt == M);\n\n        vector<int> openDoorIdx;\n        for(int i=0;i<(int)doors.size();i++){\n            if(!blocked[doors[i].x][doors[i].y]) openDoorIdx.push_back(i);\n        }\n\n        vector<char> act(M,'.');\n\n        // ---- (A) Decide builds first ----\n        // 1) Door closing phase only after walls are done.\n        int maxCloseThisTurn = 0;\n        if(remWalls==0 && !openDoorIdx.empty()){\n            if(allInside) maxCloseThisTurn = (int)openDoorIdx.size();         // close all\n            else maxCloseThisTurn = max(0, (int)openDoorIdx.size() - 1);      // keep at least one open\n        }\n\n        // Try to close doors (greedy)\n        int closedThisTurn=0;\n        for(int id: openDoorIdx){\n            if(closedThisTurn >= maxCloseThisTurn) break;\n            auto &d = doors[id];\n\n            // must be buildable by rules\n            if(!canBuild(d.x,d.y,petAt,humanAt)) continue;\n\n            // find an unassigned adjacent human\n            for(int i=0;i<M;i++){\n                if(act[i] != '.') continue;\n                int hx=humans[i].x, hy=humans[i].y;\n                if(manhattan(hx,hy,d.x,d.y)!=1) continue;\n                for(int dir=0; dir<4; dir++){\n                    if(hx+dx4[dir]==d.x && hy+dy4[dir]==d.y){\n                        act[i]=BUILD_CH[dir];\n                        break;\n                    }\n                }\n                if(act[i] != '.'){\n                    closedThisTurn++;\n                    break;\n                }\n            }\n        }\n\n        // 2) Build remaining wall cells, with reservation\n        static bool reserved[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) reserved[x][y]=false;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n\n        for(int idx=0; idx<M; idx++){\n            int i = order[idx];\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n            for(int dir=0; dir<4; dir++){\n                int tx=hx+dx4[dir], ty=hy+dy4[dir];\n                if(!inb(tx,ty)) continue;\n                if(!(targetWall[tx][ty] && !blocked[tx][ty])) continue;\n                if(reserved[tx][ty]) continue;\n                if(!canBuild(tx,ty,petAt,humanAt)) continue;\n                reserved[tx][ty]=true;\n                act[i]=BUILD_CH[dir];\n                break;\n            }\n        }\n\n        // Compute willBlock (for move legality)\n        static bool willBlock[H+1][W+1];\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) willBlock[x][y]=false;\n\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='u') dir=0;\n            if(c=='d') dir=1;\n            if(c=='l') dir=2;\n            if(c=='r') dir=3;\n            if(dir==-1) continue;\n            int tx=humans[i].x+dx4[dir], ty=humans[i].y+dy4[dir];\n            if(inb(tx,ty) && !blocked[tx][ty] && canBuild(tx,ty,petAt,humanAt)){\n                willBlock[tx][ty]=true;\n            }\n        }\n\n        // ---- (B) Movement planning (avoid willBlock) ----\n        auto passAll = [&](int x,int y)->bool{\n            return inb(x,y) && !blocked[x][y] && !willBlock[x][y];\n        };\n\n        // build goals: cells adjacent to remaining target walls\n        vector<pair<int,int>> buildGoals;\n        if(remWalls > 0){\n            static bool mark[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark[x][y]=false;\n\n            for(auto [wx,wy]: wallCells){\n                if(!(targetWall[wx][wy] && !blocked[wx][wy])) continue;\n                for(int d=0; d<4; d++){\n                    int nx=wx+dx4[d], ny=wy+dy4[d];\n                    if(inb(nx,ny) && passAll(nx,ny) && !mark[nx][ny]){\n                        mark[nx][ny]=true;\n                        buildGoals.push_back({nx,ny});\n                    }\n                }\n            }\n        }\n\n        // close goals: inside-neighbor cells of open doors (to stand near for closing)\n        vector<pair<int,int>> closeGoals;\n        if(remWalls==0 && !openDoorIdx.empty() && maxCloseThisTurn>0){\n            static bool mark2[H+1][W+1];\n            for(int x=1;x<=H;x++) for(int y=1;y<=W;y++) mark2[x][y]=false;\n            for(int id: openDoorIdx){\n                auto &d = doors[id];\n                if(!inb(d.inx,d.iny)) continue;\n                if(!passAll(d.inx,d.iny)) continue;\n                if(!mark2[d.inx][d.iny]){\n                    mark2[d.inx][d.iny]=true;\n                    closeGoals.push_back({d.inx,d.iny});\n                }\n            }\n        }\n\n        vector<vector<int>> distBuild, distGather, distClose;\n        if(!buildGoals.empty()) bfs_dist(distBuild, buildGoals, passAll);\n        else distBuild.assign(H+1, vector<int>(W+1, INF));\n\n        bfs_dist(distGather, {gather}, passAll);\n\n        if(!closeGoals.empty()) bfs_dist(distClose, closeGoals, passAll);\n        else distClose.assign(H+1, vector<int>(W+1, INF));\n\n        auto tiePenalty = [&](int x,int y)->int{\n            int pen=0;\n            if(targetWall[x][y] && !blocked[x][y]) pen += 10; // don't stand on to-be-built wall cells\n            return pen;\n        };\n\n        for(int i=0;i<M;i++){\n            if(act[i] != '.') continue;\n            int hx=humans[i].x, hy=humans[i].y;\n\n            if(remWalls > 0 && distBuild[hx][hy] < INF){\n                act[i] = step_by_dist(hx,hy,distBuild,passAll,tiePenalty);\n            } else if(!closeGoals.empty() && distClose[hx][hy] < INF){\n                act[i] = step_by_dist(hx,hy,distClose,passAll,tiePenalty);\n            } else if(!allInside && distGather[hx][hy] < INF){\n                act[i] = step_by_dist(hx,hy,distGather,passAll,tiePenalty);\n            } else {\n                act[i] = '.';\n            }\n        }\n\n        // Output\n        string out;\n        out.reserve(M);\n        for(int i=0;i<M;i++) out.push_back(act[i]);\n        cout << out << \"\\n\" << flush;\n\n        // ---- local simulation update ----\n        for(int x=1;x<=H;x++) for(int y=1;y<=W;y++){\n            if(willBlock[x][y]) blocked[x][y]=true;\n        }\n\n        for(int i=0;i<M;i++){\n            char c=act[i];\n            int dir=-1;\n            if(c=='U') dir=0;\n            if(c=='D') dir=1;\n            if(c=='L') dir=2;\n            if(c=='R') dir=3;\n            if(dir==-1) continue;\n            int nx=humans[i].x+dx4[dir], ny=humans[i].y+dy4[dir];\n            if(inb(nx,ny) && !blocked[nx][ny] && !willBlock[nx][ny]){\n                humans[i].x=nx; humans[i].y=ny;\n            }\n        }\n\n        // Read pet moves and update pets\n        for(int i=0;i<N;i++){\n            string s; cin >> s;\n            if(s==\".\") continue;\n            for(char c: s){\n                int dir=-1;\n                if(c=='U') dir=0;\n                if(c=='D') dir=1;\n                if(c=='L') dir=2;\n                if(c=='R') dir=3;\n                if(dir==-1) continue;\n                int nx=pets[i].x+dx4[dir], ny=pets[i].y+dy4[dir];\n                if(inb(nx,ny) && !blocked[nx][ny]){\n                    pets[i].x=nx; pets[i].y=ny;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int V = N * N;\nstatic constexpr int L = 200;\nstatic constexpr int INF = 1e9;\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() : st(chrono::high_resolution_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstatic inline int dirId(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    return 3;\n}\nstatic inline char dirCh(int d) {\n    static const char dc[4] = {'U','D','L','R'};\n    return dc[d];\n}\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct XorShift {\n    uint64_t s0, s1;\n    XorShift(uint64_t seed = 1) { reseed(seed); }\n    void reseed(uint64_t seed) {\n        s0 = splitmix64(seed);\n        s1 = splitmix64(s0);\n        if ((s0 | s1) == 0) s1 = 1;\n    }\n    uint64_t nextU64() {\n        uint64_t x = s0, y = s1;\n        s0 = y;\n        x ^= x << 23;\n        s1 = x ^ y ^ (x >> 17) ^ (y >> 26);\n        return s1 + y;\n    }\n    uint32_t nextU32() { return (uint32_t)(nextU64() >> 32); }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n    double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic string pad_to_200(string s) {\n    if ((int)s.size() >= L) { s.resize(L); return s; }\n    if (s.empty()) return string(L, 'U');\n    s.resize(L, s.back());\n    return s;\n}\nstatic string tile_to_200(const string &base) {\n    if (base.empty()) return string(L, 'U');\n    string out; out.reserve(L);\n    while ((int)out.size() < L) out += base;\n    out.resize(L);\n    return out;\n}\nstatic string stretch_runs_to_200(const string &path, int factor) {\n    if (path.empty()) return string(L, 'U');\n    string out; out.reserve(L);\n    for (int i = 0; i < (int)path.size() && (int)out.size() < L; ) {\n        int j = i;\n        while (j < (int)path.size() && path[j] == path[i]) j++;\n        int len = (j - i) * factor;\n        for (int k = 0; k < len && (int)out.size() < L; k++) out.push_back(path[i]);\n        i = j;\n    }\n    while ((int)out.size() < L) out.push_back(path.back());\n    return out;\n}\n\nstruct EvaluatorFullDouble {\n    int s, t;\n    double p, q;\n    const int (*nxt)[4];\n    vector<double> dist, ndist;\n    EvaluatorFullDouble(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p(p_), q(1.0 - p_), nxt(nxt_) {\n        dist.assign(V, 0.0);\n        ndist.assign(V, 0.0);\n    }\n    double eval(const string &seq) {\n        fill(dist.begin(), dist.end(), 0.0);\n        dist[s] = 1.0;\n        double E = 0.0;\n        for (int step = 0; step < (int)seq.size(); step++) {\n            fill(ndist.begin(), ndist.end(), 0.0);\n            int d = dirId(seq[step]);\n            double hit = 0.0;\n            for (int pos = 0; pos < V; pos++) {\n                double pr = dist[pos];\n                if (pr <= 0.0) continue;\n                int np = nxt[pos][d];\n                if (np == pos) ndist[pos] += pr;\n                else {\n                    double st = pr * p;\n                    double mv = pr * q;\n                    ndist[pos] += st;\n                    if (np == t) hit += mv;\n                    else ndist[np] += mv;\n                }\n            }\n            dist.swap(ndist);\n            E += hit * (401.0 - (step + 1));\n        }\n        return E;\n    }\n};\n\n// ===== Constructors =====\n\nstatic string bfs_shortest_path(int s, int t, const int nxt[V][4]) {\n    vector<int> prev(V, -1);\n    vector<char> prevC(V, '?');\n    deque<int> dq;\n    dq.push_back(s);\n    prev[s] = s;\n    while (!dq.empty()) {\n        int x = dq.front(); dq.pop_front();\n        if (x == t) break;\n        for (int d = 0; d < 4; d++) {\n            int y = nxt[x][d];\n            if (y == x) continue;\n            if (prev[y] != -1) continue;\n            prev[y] = x;\n            prevC[y] = dirCh(d);\n            dq.push_back(y);\n        }\n    }\n    if (prev[t] == -1) return \"D\";\n    string path;\n    int cur = t;\n    while (cur != s) {\n        path.push_back(prevC[cur]);\n        cur = prev[cur];\n    }\n    reverse(path.begin(), path.end());\n    if (path.empty()) path = \"D\";\n    return path;\n}\n\n// Dijkstra on (cell, prevDir) minimizing length + turnPenalty*turns\nstatic string min_turn_path(int s, int t, const int nxt[V][4], int turnPenalty) {\n    const int PD = 5; // 0..3 prevDir, 4=start\n    int S = s * PD + 4;\n\n    vector<int> dist(V * PD, INF);\n    vector<int> prv(V * PD, -1);\n    vector<char> prvMove(V * PD, '?');\n\n    using P = pair<int,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    dist[S] = 0;\n    pq.push({0, S});\n\n    int bestEnd = -1;\n    while (!pq.empty()) {\n        auto [cd, st] = pq.top(); pq.pop();\n        if (cd != dist[st]) continue;\n        int cell = st / PD;\n        int prevDir = st % PD;\n        if (cell == t) { bestEnd = st; break; }\n\n        for (int d = 0; d < 4; d++) {\n            int nc = nxt[cell][d];\n            if (nc == cell) continue;\n            int ns = nc * PD + d;\n            int add = 1;\n            if (prevDir != 4 && prevDir != d) add += turnPenalty;\n            int nd = cd + add;\n            if (nd < dist[ns]) {\n                dist[ns] = nd;\n                prv[ns] = st;\n                prvMove[ns] = dirCh(d);\n                pq.push({nd, ns});\n            }\n        }\n    }\n\n    if (bestEnd == -1) return bfs_shortest_path(s, t, nxt);\n\n    string path;\n    int cur = bestEnd;\n    while (cur != S) {\n        path.push_back(prvMove[cur]);\n        cur = prv[cur];\n    }\n    reverse(path.begin(), path.end());\n    if (path.empty()) path = \"D\";\n    return path;\n}\n\nstatic string greedy_lookahead_200(int s, int t, double p, const int nxt[V][4], const vector<int>& distToT) {\n    double q = 1.0 - p;\n    vector<double> cur(V, 0.0), nd(V, 0.0);\n    cur[s] = 1.0;\n\n    string out; out.reserve(L);\n    for (int step = 0; step < L; step++) {\n        int bestD = 0;\n        double bestVal = -1e100;\n\n        for (int d = 0; d < 4; d++) {\n            fill(nd.begin(), nd.end(), 0.0);\n            double hit = 0.0, expDist = 0.0;\n            for (int pos = 0; pos < V; pos++) {\n                double pr = cur[pos];\n                if (pr <= 0.0) continue;\n                int np = nxt[pos][d];\n                if (np == pos) nd[pos] += pr;\n                else {\n                    double st = pr * p;\n                    double mv = pr * q;\n                    nd[pos] += st;\n                    if (np == t) hit += mv;\n                    else nd[np] += mv;\n                }\n            }\n            for (int pos = 0; pos < V; pos++) expDist += nd[pos] * distToT[pos];\n            double val = 0.30 * (401.0 - (step + 1)) * hit - 1.7 * expDist;\n            if (val > bestVal) { bestVal = val; bestD = d; }\n        }\n\n        // apply bestD\n        fill(nd.begin(), nd.end(), 0.0);\n        for (int pos = 0; pos < V; pos++) {\n            double pr = cur[pos];\n            if (pr <= 0.0) continue;\n            int np = nxt[pos][bestD];\n            if (np == pos) nd[pos] += pr;\n            else {\n                double st = pr * p;\n                double mv = pr * q;\n                nd[pos] += st;\n                if (np != t) nd[np] += mv;\n            }\n        }\n        cur.swap(nd);\n        out.push_back(dirCh(bestD));\n    }\n    return out;\n}\n\n// ===== Beam Search =====\n\nstruct Meta { int parent; char mv; };\nstruct BeamCand {\n    int meta;\n    double exp;\n    double key;\n    double rem;\n    array<double, V> prob;\n};\n\nstatic string beam_search_200(\n    int s, int t, double p, const int nxt[V][4], const vector<int>& distToT,\n    Timer &timer, double endTime, XorShift &rng\n) {\n    double q = 1.0 - p;\n    int W = (p >= 0.35 ? 850 : 700); // slightly reduced (more SA time)\n    int keepKey = (int)(W * 0.55);\n    int keepExp = (int)(W * 0.25);\n    int keepRem = W - keepKey - keepExp;\n\n    vector<Meta> meta;\n    meta.reserve(240000);\n    meta.push_back({-1, '?'});\n\n    vector<BeamCand> cur;\n    cur.reserve(W);\n\n    BeamCand root;\n    root.meta = 0;\n    root.exp = 0.0;\n    root.key = 0.0;\n    root.rem = 1.0;\n    root.prob.fill(0.0);\n    root.prob[s] = 1.0;\n    cur.push_back(root);\n\n    for (int depth = 0; depth < L; depth++) {\n        if (timer.elapsed() > endTime) break;\n\n        vector<BeamCand> all;\n        all.reserve(cur.size() * 4);\n\n        for (auto &c : cur) {\n            if (c.rem < 1e-15) continue;\n            for (int d = 0; d < 4; d++) {\n                BeamCand ch;\n                ch.prob.fill(0.0);\n                double hit = 0.0;\n\n                for (int pos = 0; pos < V; pos++) {\n                    double pr = c.prob[pos];\n                    if (pr <= 0.0) continue;\n                    int np = nxt[pos][d];\n                    if (np == pos) ch.prob[pos] += pr;\n                    else {\n                        double st = pr * p;\n                        double mv = pr * q;\n                        ch.prob[pos] += st;\n                        if (np == t) hit += mv;\n                        else ch.prob[np] += mv;\n                    }\n                }\n\n                int turn = depth + 1;\n                ch.exp = c.exp + hit * (401.0 - turn);\n\n                double rem = 0.0, sumd = 0.0;\n                int mind = INF;\n                for (int pos = 0; pos < V; pos++) {\n                    double pr = ch.prob[pos];\n                    if (pr <= 0.0) continue;\n                    rem += pr;\n                    sumd += pr * distToT[pos];\n                    mind = min(mind, distToT[pos]);\n                }\n                ch.rem = rem;\n\n                double key = ch.exp;\n                int remainingSteps = L - turn;\n                if (rem > 1e-15 && mind <= remainingSteps) {\n                    double avgd = sumd / rem;\n                    double estTime = (double)turn + avgd / max(1e-9, q);\n                    estTime = min(estTime, 200.0);\n                    double estAdd = rem * max(0.0, 401.0 - estTime);\n                    key = ch.exp + 0.85 * estAdd + 8.0 * (1.0 - rem);\n                }\n                key += (rng.nextDouble() - 0.5) * 1e-6;\n                ch.key = key;\n\n                meta.push_back({c.meta, dirCh(d)});\n                ch.meta = (int)meta.size() - 1;\n\n                all.push_back(std::move(ch));\n            }\n        }\n        if (all.empty()) break;\n\n        int M = (int)all.size();\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        vector<char> chosen(M, 0);\n        vector<int> picked;\n        picked.reserve(min(W, M));\n\n        auto pickTop = [&](int need, auto cmp) {\n            if (need <= 0) return;\n            vector<int> id = idx;\n            need = min(need, (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(), cmp);\n            id.resize(need);\n            sort(id.begin(), id.end(), cmp);\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) { chosen[i] = 1; picked.push_back(i); }\n            }\n        };\n\n        pickTop(keepKey, [&](int a, int b){ return all[a].key > all[b].key; });\n        pickTop(keepExp, [&](int a, int b){ return all[a].exp > all[b].exp; });\n        pickTop(keepRem, [&](int a, int b){ return all[a].rem < all[b].rem; });\n\n        if ((int)picked.size() < min(W, M)) {\n            vector<int> id = idx;\n            int need = min(W - (int)picked.size(), (int)id.size());\n            nth_element(id.begin(), id.begin() + need, id.end(),\n                        [&](int a, int b){ return all[a].key > all[b].key; });\n            id.resize(need);\n            sort(id.begin(), id.end(), [&](int a, int b){ return all[a].key > all[b].key; });\n            for (int i : id) {\n                if ((int)picked.size() >= W) break;\n                if (!chosen[i]) { chosen[i] = 1; picked.push_back(i); }\n            }\n        }\n\n        vector<BeamCand> nb;\n        nb.reserve(picked.size());\n        for (int i : picked) nb.push_back(std::move(all[i]));\n        cur.swap(nb);\n    }\n\n    int bestMeta = cur[0].meta;\n    double bestExp = cur[0].exp;\n    for (auto &c : cur) if (c.exp > bestExp) { bestExp = c.exp; bestMeta = c.meta; }\n\n    string ans;\n    int node = bestMeta;\n    while (node != 0) {\n        ans.push_back(meta[node].mv);\n        node = meta[node].parent;\n    }\n    reverse(ans.begin(), ans.end());\n    return pad_to_200(ans);\n}\n\n// ===== DP for O(V) deltaSingle / deltaPair =====\n\nstruct DPAll {\n    int s, t;\n    float p, q;\n    const int (*nxt)[4];\n\n    string seq;                 // length L\n    vector<float> dist;         // (L+1)*V\n    vector<double> B;           // (L+1)*V\n    double score;               // expected score = B[0][s]\n\n    DPAll(int s_, int t_, double p_, const int (*nxt_)[4])\n        : s(s_), t(t_), p((float)p_), q((float)(1.0 - p_)), nxt(nxt_) {\n        seq.assign(L, 'U');\n        dist.assign((L + 1) * V, 0.0f);\n        B.assign((L + 1) * V, 0.0);\n        score = 0.0;\n    }\n\n    inline float* distAt(int k) { return dist.data() + k * V; }\n    inline const float* distAt(int k) const { return dist.data() + k * V; }\n    inline double* BAt(int k) { return B.data() + k * V; }\n    inline const double* BAt(int k) const { return B.data() + k * V; }\n\n    void build(const string &init) {\n        seq = init;\n        fill(dist.begin(), dist.end(), 0.0f);\n        distAt(0)[s] = 1.0f;\n\n        for (int k = 0; k < L; k++) {\n            const float* cur = distAt(k);\n            float* nx = distAt(k + 1);\n            memset(nx, 0, sizeof(float) * V);\n            int d = dirId(seq[k]);\n            for (int pos = 0; pos < V; pos++) {\n                float pr = cur[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) nx[pos] += pr;\n                else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    nx[pos] += st;\n                    if (np != t) nx[np] += mv;\n                }\n            }\n        }\n\n        // B[L]=0\n        {\n            double* BL = BAt(L);\n            for (int pos = 0; pos < V; pos++) BL[pos] = 0.0;\n        }\n        for (int k = L - 1; k >= 0; k--) {\n            const double* Bnext = BAt(k + 1);\n            double* Bcur = BAt(k);\n            int d = dirId(seq[k]);\n            double reward = (401.0 - (k + 1));\n            for (int pos = 0; pos < V; pos++) {\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    Bcur[pos] = Bnext[pos];\n                } else {\n                    double val = (double)p * Bnext[pos];\n                    if (np == t) val += (double)q * reward;\n                    else val += (double)q * Bnext[np];\n                    Bcur[pos] = val;\n                }\n            }\n        }\n        score = BAt(0)[s];\n    }\n\n    void forwardUpdate(int from) {\n        for (int k = from; k < L; k++) {\n            const float* cur = distAt(k);\n            float* nx = distAt(k + 1);\n            memset(nx, 0, sizeof(float) * V);\n            int d = dirId(seq[k]);\n            for (int pos = 0; pos < V; pos++) {\n                float pr = cur[pos];\n                if (pr <= 0.0f) continue;\n                int np = nxt[pos][d];\n                if (np == pos) nx[pos] += pr;\n                else {\n                    float st = pr * p;\n                    float mv = pr * q;\n                    nx[pos] += st;\n                    if (np != t) nx[np] += mv;\n                }\n            }\n        }\n    }\n\n    void backwardUpdate(int from) {\n        for (int k = from; k >= 0; k--) {\n            const double* Bnext = BAt(k + 1);\n            double* Bcur = BAt(k);\n            int d = dirId(seq[k]);\n            double reward = (401.0 - (k + 1));\n            for (int pos = 0; pos < V; pos++) {\n                int np = nxt[pos][d];\n                if (np == pos) {\n                    Bcur[pos] = Bnext[pos];\n                } else {\n                    double val = (double)p * Bnext[pos];\n                    if (np == t) val += (double)q * reward;\n                    else val += (double)q * Bnext[np];\n                    Bcur[pos] = val;\n                }\n            }\n        }\n    }\n\n    inline double oneStepVal(int pos, int d, const double* Bnext, double reward) const {\n        int np = nxt[pos][d];\n        if (np == pos) return Bnext[pos];\n        double val = (double)p * Bnext[pos];\n        if (np == t) val += (double)q * reward;\n        else val += (double)q * Bnext[np];\n        return val;\n    }\n\n    double deltaSingle(int idx, char newc) const {\n        int dOld = dirId(seq[idx]);\n        int dNew = dirId(newc);\n        if (dOld == dNew) return 0.0;\n\n        const float* di = distAt(idx);\n        const double* Bnext = BAt(idx + 1);\n        double reward = (401.0 - (idx + 1));\n\n        double delta = 0.0;\n        for (int pos = 0; pos < V; pos++) {\n            float pr = di[pos];\n            if (pr <= 0.0f) continue;\n            delta += (double)pr * (oneStepVal(pos, dNew, Bnext, reward) - oneStepVal(pos, dOld, Bnext, reward));\n        }\n        return delta;\n    }\n\n    double deltaPair(int idx, char c1, char c2) const {\n        int d1Old = dirId(seq[idx]);\n        int d2Old = dirId(seq[idx + 1]);\n        int d1New = dirId(c1);\n        int d2New = dirId(c2);\n        if (d1Old == d1New && d2Old == d2New) return 0.0;\n\n        const float* di = distAt(idx);\n        const double* B2 = BAt(idx + 2);\n        double r1 = (401.0 - (idx + 1));\n        double r2 = (401.0 - (idx + 2));\n\n        auto pairVal = [&](int pos, int d1, int d2) -> double {\n            int np1 = nxt[pos][d1];\n            if (np1 == pos) {\n                return oneStepVal(pos, d2, B2, r2);\n            } else {\n                double val = (double)p * oneStepVal(pos, d2, B2, r2);\n                if (np1 == t) val += (double)q * r1;\n                else val += (double)q * oneStepVal(np1, d2, B2, r2);\n                return val;\n            }\n        };\n\n        double delta = 0.0;\n        for (int pos = 0; pos < V; pos++) {\n            float pr = di[pos];\n            if (pr <= 0.0f) continue;\n            delta += (double)pr * (pairVal(pos, d1New, d2New) - pairVal(pos, d1Old, d2Old));\n        }\n        return delta;\n    }\n\n    void applySingleAccepted(int idx, char newc) {\n        seq[idx] = newc;\n        forwardUpdate(idx);\n        backwardUpdate(idx);\n        score = BAt(0)[s];\n    }\n    void applyPairAccepted(int idx, char c1, char c2) {\n        seq[idx] = c1;\n        seq[idx + 1] = c2;\n        forwardUpdate(idx);\n        backwardUpdate(idx + 1);\n        score = BAt(0)[s];\n    }\n    void applySegmentChanged(int l, int r) {\n        l = max(l, 0);\n        r = min(r, L);\n        if (l >= r) return;\n        forwardUpdate(l);\n        backwardUpdate(r - 1);\n        score = BAt(0)[s];\n    }\n};\n\n// Greedy sweep: single edits on suffix, only apply meaningful deltas\nstatic void greedySuffixSingle(DPAll &dp, int startIdx, Timer &timer, double endTime, double minDelta) {\n    startIdx = max(0, min(L - 1, startIdx));\n    for (int idx = L - 1; idx >= startIdx; idx--) {\n        if (timer.elapsed() > endTime) return;\n        char orig = dp.seq[idx];\n        double bestDelta = 0.0;\n        char bestC = orig;\n        for (int d = 0; d < 4; d++) {\n            char c = dirCh(d);\n            if (c == orig) continue;\n            double delta = dp.deltaSingle(idx, c);\n            if (delta > bestDelta) { bestDelta = delta; bestC = c; }\n        }\n        if (bestC != orig && bestDelta >= minDelta) dp.applySingleAccepted(idx, bestC);\n    }\n}\n\n// Very limited greedy pair improvements on a suffix at turns\nstatic void greedySuffixPairLimited(DPAll &dp, int startIdx, Timer &timer, double endTime, double minDelta, int maxApply) {\n    startIdx = max(0, min(L - 2, startIdx));\n    int applied = 0;\n    for (int idx = L - 2; idx >= startIdx; idx--) {\n        if (timer.elapsed() > endTime) return;\n        if (applied >= maxApply) return;\n        if (dp.seq[idx] == dp.seq[idx + 1]) continue; // focus on corners\n\n        char o1 = dp.seq[idx], o2 = dp.seq[idx + 1];\n        double bestDelta = 0.0;\n        char b1 = o1, b2 = o2;\n\n        // best-of-16\n        for (int d1 = 0; d1 < 4; d1++) for (int d2 = 0; d2 < 4; d2++) {\n            char c1 = dirCh(d1), c2 = dirCh(d2);\n            double delta = dp.deltaPair(idx, c1, c2);\n            if (delta > bestDelta) { bestDelta = delta; b1 = c1; b2 = c2; }\n        }\n        if ((b1 != o1 || b2 != o2) && bestDelta >= minDelta) {\n            dp.applyPairAccepted(idx, b1, b2);\n            applied++;\n        }\n    }\n}\n\nstatic void SA_fastDelta_pairOnly(\n    DPAll &dp,\n    Timer &timer,\n    double endTime,\n    XorShift &rng,\n    string &bestSeqOut,\n    double &bestScoreOut\n) {\n    double bestIncSeen = dp.score;\n    bestSeqOut = dp.seq;\n    bestScoreOut = dp.score;\n\n    int stagn = 0;\n\n    auto sampleIndex = [&]() {\n        if (rng.nextDouble() < 0.35) return rng.nextInt(0, L - 1);\n        int a = rng.nextInt(0, L - 1);\n        int b = rng.nextInt(0, L - 1);\n        return max(a, b);\n    };\n    auto sampleTurnIndex = [&]() -> int {\n        for (int it = 0; it < 8; it++) {\n            int i = rng.nextInt(1, L - 2);\n            if (dp.seq[i] != dp.seq[i - 1] || dp.seq[i] != dp.seq[i + 1]) return i;\n        }\n        return sampleIndex();\n    };\n    auto sampleTurnPair = [&]() -> int {\n        for (int it = 0; it < 8; it++) {\n            int i = rng.nextInt(0, L - 2);\n            if (dp.seq[i] != dp.seq[i + 1]) return i;\n        }\n        return rng.nextInt(0, L - 2);\n    };\n\n    while (timer.elapsed() < endTime) {\n        double now = timer.elapsed();\n        double frac = min(1.0, max(0.0, (now - (endTime - 1.0)) / max(1e-9, 1.0)));\n        double T0 = 4.1, T1 = 0.055;\n        if (stagn > 10000) T0 *= 1.12;\n        double temp = T0 * pow(T1 / T0, frac);\n\n        int r = rng.nextInt(0, 999);\n\n        if (r < 860) {\n            // single\n            int idx = sampleTurnIndex();\n            char orig = dp.seq[idx];\n            char nc = orig;\n\n            int type = rng.nextInt(0, 9);\n            if (type <= 4) {\n                do { nc = dirCh(rng.nextInt(0, 3)); } while (nc == orig);\n            } else if (type <= 7) {\n                if (idx == 0) nc = dp.seq[1];\n                else if (idx == L - 1) nc = dp.seq[L - 2];\n                else nc = (rng.nextDouble() < 0.5 ? dp.seq[idx - 1] : dp.seq[idx + 1]);\n                if (nc == orig) { stagn++; continue; }\n            } else {\n                // greedy best-of-4\n                double bestDelta = -1e100;\n                char bestC = orig;\n                for (int d = 0; d < 4; d++) {\n                    char c = dirCh(d);\n                    double delta = dp.deltaSingle(idx, c);\n                    if (delta > bestDelta) { bestDelta = delta; bestC = c; }\n                }\n                nc = bestC;\n                if (nc == orig) { stagn++; continue; }\n            }\n\n            double delta = dp.deltaSingle(idx, nc);\n            if (delta == 0.0) { stagn++; continue; }\n\n            bool accept = (delta >= 0) || (exp(delta / temp) > rng.nextDouble());\n            if (!accept) { stagn++; continue; }\n\n            dp.applySingleAccepted(idx, nc);\n\n        } else if (r < 990) {\n            // pair (more frequent than segment)\n            int idx = sampleTurnPair();\n            char o1 = dp.seq[idx], o2 = dp.seq[idx + 1];\n            char n1 = o1, n2 = o2;\n\n            int type = rng.nextInt(0, 9);\n            if (type <= 5) {\n                // swap\n                n1 = o2; n2 = o1;\n            } else if (type <= 7) {\n                // flatten to neighbor direction\n                char fillc;\n                if (idx > 0 && rng.nextDouble() < 0.5) fillc = dp.seq[idx - 1];\n                else if (idx + 2 < L) fillc = dp.seq[idx + 2];\n                else fillc = o1;\n                n1 = fillc; n2 = fillc;\n            } else if (type == 8) {\n                n1 = dirCh(rng.nextInt(0, 3));\n                n2 = dirCh(rng.nextInt(0, 3));\n            } else {\n                // best-of-16 (rare)\n                double bestDelta = -1e100;\n                char b1 = o1, b2 = o2;\n                for (int d1 = 0; d1 < 4; d1++) for (int d2 = 0; d2 < 4; d2++) {\n                    char c1 = dirCh(d1), c2 = dirCh(d2);\n                    double delta = dp.deltaPair(idx, c1, c2);\n                    if (delta > bestDelta) { bestDelta = delta; b1 = c1; b2 = c2; }\n                }\n                n1 = b1; n2 = b2;\n            }\n\n            if (n1 == o1 && n2 == o2) { stagn++; continue; }\n            double delta = dp.deltaPair(idx, n1, n2);\n            if (delta == 0.0) { stagn++; continue; }\n\n            bool accept = (delta >= 0) || (exp(delta / temp) > rng.nextDouble());\n            if (!accept) { stagn++; continue; }\n\n            dp.applyPairAccepted(idx, n1, n2);\n\n        } else {\n            // very rare segment (expensive)\n            int l = rng.nextInt(0, L - 2);\n            int rr = rng.nextInt(l + 1, min(L - 1, l + 30));\n            int len = rr - l + 1;\n\n            string old = dp.seq.substr(l, len);\n            double oldScore = dp.score;\n\n            int type = rng.nextInt(0, 2);\n            if (type == 0) {\n                for (int i = l; i <= rr; i++) dp.seq[i] = dirCh(rng.nextInt(0, 3));\n            } else if (type == 1) {\n                reverse(dp.seq.begin() + l, dp.seq.begin() + rr + 1);\n            } else {\n                char last = dp.seq[rr];\n                for (int i = rr; i > l; i--) dp.seq[i] = dp.seq[i - 1];\n                dp.seq[l] = last;\n            }\n\n            dp.applySegmentChanged(l, rr + 1);\n            double delta = dp.score - oldScore;\n\n            bool accept = (delta >= 0) || (exp(delta / temp) > rng.nextDouble());\n            if (!accept) {\n                for (int i = 0; i < len; i++) dp.seq[l + i] = old[i];\n                dp.applySegmentChanged(l, rr + 1);\n                stagn++;\n                continue;\n            }\n        }\n\n        // update best tracking (no full-eval here; we will full-eval only at the end)\n        if (dp.score > bestIncSeen + 1e-9) {\n            bestIncSeen = dp.score;\n            bestSeqOut = dp.seq;\n            bestScoreOut = dp.score;\n            stagn = 0;\n        } else {\n            stagn++;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TL = 1.97;\n    const double BEAM_END = 0.50; // more SA time\n\n    int si, sj, ti, tj;\n    double p;\n    cin >> si >> sj >> ti >> tj >> p;\n\n    vector<string> h(N);\n    for (int i = 0; i < N; i++) cin >> h[i];\n    vector<string> v(N - 1);\n    for (int i = 0; i < N - 1; i++) cin >> v[i];\n\n    auto id = [&](int r, int c){ return r * N + c; };\n    int s = id(si, sj);\n    int t = id(ti, tj);\n\n    static int nxt[V][4];\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int cur = id(r, c);\n        // U\n        if (r == 0) nxt[cur][0] = cur;\n        else nxt[cur][0] = (v[r-1][c] == '0') ? id(r-1, c) : cur;\n        // D\n        if (r == N-1) nxt[cur][1] = cur;\n        else nxt[cur][1] = (v[r][c] == '0') ? id(r+1, c) : cur;\n        // L\n        if (c == 0) nxt[cur][2] = cur;\n        else nxt[cur][2] = (h[r][c-1] == '0') ? id(r, c-1) : cur;\n        // R\n        if (c == N-1) nxt[cur][3] = cur;\n        else nxt[cur][3] = (h[r][c] == '0') ? id(r, c+1) : cur;\n    }\n\n    // dist-to-target for heuristics\n    vector<int> distToT(V, INF);\n    {\n        deque<int> dq;\n        distToT[t] = 0;\n        dq.push_back(t);\n        while (!dq.empty()) {\n            int x = dq.front(); dq.pop_front();\n            int dx = distToT[x] + 1;\n            for (int d = 0; d < 4; d++) {\n                int y = nxt[x][d];\n                if (y == x) continue;\n                if (distToT[y] > dx) {\n                    distToT[y] = dx;\n                    dq.push_back(y);\n                }\n            }\n        }\n    }\n\n    // deterministic seed\n    uint64_t seed = 0;\n    seed = splitmix64(seed ^ (uint64_t)si);\n    seed = splitmix64(seed ^ (uint64_t)sj);\n    seed = splitmix64(seed ^ (uint64_t)ti);\n    seed = splitmix64(seed ^ (uint64_t)tj);\n    seed = splitmix64(seed ^ (uint64_t)llround(p * 1000000.0));\n    for (auto &row : h) for (char c : row) seed = splitmix64(seed ^ (uint64_t)c);\n    for (auto &row : v) for (char c : row) seed = splitmix64(seed ^ (uint64_t)c);\n    XorShift rng(seed);\n\n    EvaluatorFullDouble fullEval(s, t, p, nxt);\n\n    // initial candidates\n    vector<string> cands;\n    cands.reserve(64);\n\n    string sp = bfs_shortest_path(s, t, nxt);\n    cands.push_back(tile_to_200(sp));\n    cands.push_back(stretch_runs_to_200(sp, 2));\n    cands.push_back(stretch_runs_to_200(sp, 3));\n    cands.push_back(pad_to_200(sp));\n\n    for (int tp : {2, 5, 10, 20, 40}) {\n        string mt = min_turn_path(s, t, nxt, tp);\n        cands.push_back(tile_to_200(mt));\n        cands.push_back(stretch_runs_to_200(mt, 2));\n        cands.push_back(stretch_runs_to_200(mt, 3));\n        cands.push_back(pad_to_200(mt));\n    }\n\n    cands.push_back(greedy_lookahead_200(s, t, p, nxt, distToT));\n    cands.push_back(beam_search_200(s, t, p, nxt, distToT, timer, BEAM_END, rng));\n\n    // rank by full eval\n    vector<pair<double,string>> scored;\n    scored.reserve(cands.size());\n    for (auto &ss : cands) scored.push_back({fullEval.eval(ss), ss});\n    sort(scored.begin(), scored.end(), [&](auto &a, auto &b){ return a.first > b.first; });\n\n    // multi-start SA on top K\n    int K = min(4, (int)scored.size());\n    vector<double> w(K, 0.0);\n    if (K == 1) w[0] = 1.0;\n    else if (K == 2) { w[0] = 0.72; w[1] = 0.28; }\n    else if (K == 3) { w[0] = 0.70; w[1] = 0.20; w[2] = 0.10; }\n    else { w[0] = 0.66; w[1] = 0.18; w[2] = 0.10; w[3] = 0.06; }\n\n    double start = timer.elapsed();\n    double remaining = TL - start;\n    if (remaining < 0.03) {\n        cout << pad_to_200(scored[0].second) << \"\\n\";\n        return 0;\n    }\n\n    // collect best candidates from SA (judged by dp.score), then finalize by fullEval\n    vector<string> finalCandidates;\n    finalCandidates.reserve(K + 2);\n    finalCandidates.push_back(pad_to_200(scored[0].second));\n\n    int sweepStart = (p >= 0.35 ? 60 : 70);\n\n    for (int k = 0; k < K; k++) {\n        if (timer.elapsed() >= TL) break;\n\n        double slice = remaining * w[k];\n        double endTime = min(TL, timer.elapsed() + slice);\n\n        DPAll dp(s, t, p, nxt);\n        dp.build(pad_to_200(scored[k].second));\n\n        // short greedy sweep: single then very limited pair\n        double sweepEnd = min(endTime, timer.elapsed() + 0.05);\n        greedySuffixSingle(dp, sweepStart, timer, sweepEnd, 1e-4);\n        greedySuffixPairLimited(dp, sweepStart, timer, sweepEnd, 2e-4, 6);\n\n        string bestSeq;\n        double bestScore;\n        XorShift localRng(splitmix64(seed ^ (uint64_t)k ^ 0x123456789abcdef0ULL));\n        SA_fastDelta_pairOnly(dp, timer, endTime, localRng, bestSeq, bestScore);\n\n        finalCandidates.push_back(bestSeq);\n    }\n\n    // dedup + pick best by full evaluator (few calls)\n    sort(finalCandidates.begin(), finalCandidates.end());\n    finalCandidates.erase(unique(finalCandidates.begin(), finalCandidates.end()), finalCandidates.end());\n\n    double bestFull = -1e100;\n    string bestStr = finalCandidates[0];\n    for (auto &cand : finalCandidates) {\n        double sc = fullEval.eval(cand);\n        if (sc > bestFull) { bestFull = sc; bestStr = cand; }\n    }\n\n    cout << pad_to_200(bestStr) << \"\\n\";\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TILES = N * N;\nstatic constexpr int PORTS = TILES * 4;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU64() % (uint64_t)(hi - lo + 1));\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct EvalResult {\n    long long baseScore;     // L1*L2 (true score if >=2 loops else 0)\n    int L1, L2;\n    int loopCount;\n    int compCount;\n    int matchedEdges;        // active-active borders\n    int openEnds;            // endpoints with deg==1\n    int largestCompLen;      // max(compSize/2) over all components (loops or paths)\n    long long sumCompLenSq;  // sum (compLen^2) over all components\n    double energy;           // SA energy\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Input\n    vector<uint8_t> initState(TILES);\n    for (int i = 0; i < N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < N; j++) initState[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    // Rotation map (90deg CCW)\n    // 0->1->2->3->0, 4<->5, 6<->7\n    array<uint8_t, 8> rot1 = {1,2,3,0,5,4,7,6};\n    uint8_t rotStep[8][4];\n    for (int t = 0; t < 8; t++) {\n        rotStep[t][0] = (uint8_t)t;\n        rotStep[t][1] = rot1[t];\n        rotStep[t][2] = rot1[rotStep[t][1]];\n        rotStep[t][3] = rot1[rotStep[t][2]];\n    }\n\n    // side masks (L,U,R,D) bits 0..3, and internal pairings\n    uint8_t sideMask[8];\n    uint8_t pairCnt[8];\n    uint8_t pairs[8][2][2]; // up to 2 segments (each a pair of sides)\n\n    auto set1 = [&](int t, int a, int b, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 1;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = pairs[t][1][1] = 255;\n    };\n    auto set2 = [&](int t, int a, int b, int c, int d, uint8_t mask) {\n        sideMask[t] = mask;\n        pairCnt[t] = 2;\n        pairs[t][0][0] = (uint8_t)a;\n        pairs[t][0][1] = (uint8_t)b;\n        pairs[t][1][0] = (uint8_t)c;\n        pairs[t][1][1] = (uint8_t)d;\n    };\n\n    // 0: L-U\n    set1(0, 0, 1, (1u<<0) | (1u<<1));\n    // 1: L-D\n    set1(1, 0, 3, (1u<<0) | (1u<<3));\n    // 2: R-D\n    set1(2, 2, 3, (1u<<2) | (1u<<3));\n    // 3: U-R\n    set1(3, 1, 2, (1u<<1) | (1u<<2));\n    // 4: (L-U) and (R-D)\n    set2(4, 0, 1, 2, 3, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 5: (L-D) and (U-R)\n    set2(5, 0, 3, 1, 2, (1u<<0)|(1u<<1)|(1u<<2)|(1u<<3));\n    // 6: L-R\n    set1(6, 0, 2, (1u<<0) | (1u<<2));\n    // 7: U-D\n    set1(7, 1, 3, (1u<<1) | (1u<<3));\n\n    auto applyFromInit = [&](int idx, uint8_t r) -> uint8_t {\n        return rotStep[initState[idx]][r & 3];\n    };\n\n    // RNG\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    XorShift64 rng(seed);\n\n    // Current state\n    vector<uint8_t> curRot(TILES, 0);\n    vector<uint8_t> curState(TILES, 0);\n    vector<uint8_t> curMask(TILES, 0);\n\n    // indices of 4/5 tiles (pairing-changing tiles)\n    vector<int> pairTiles;\n    pairTiles.reserve(TILES);\n    for (int p = 0; p < TILES; p++) {\n        if (initState[p] == 4 || initState[p] == 5) pairTiles.push_back(p);\n    }\n\n    // Random init\n    for (int p = 0; p < TILES; p++) {\n        uint8_t r = (uint8_t)rng.nextInt(0, 3);\n        curRot[p] = r;\n        curState[p] = applyFromInit(p, r);\n        curMask[p] = sideMask[curState[p]];\n    }\n\n    // Greedy init:\n    // - reward active-active matches\n    // - penalize mismatch\n    // - penalize boundary leaks\n    // - add pairing potential for 4/5 tiles (and generally for any tile's internal pairs)\n    auto cont = [&](int p, int side) -> int {\n        int i = p / N, j = p % N;\n        if (side == 0) { // L\n            if (j == 0) return 0;\n            return (curMask[p - 1] & (1u << 2)) ? 1 : 0;\n        } else if (side == 1) { // U\n            if (i == 0) return 0;\n            return (curMask[p - N] & (1u << 3)) ? 1 : 0;\n        } else if (side == 2) { // R\n            if (j == N - 1) return 0;\n            return (curMask[p + 1] & (1u << 0)) ? 1 : 0;\n        } else { // D\n            if (i == N - 1) return 0;\n            return (curMask[p + N] & (1u << 1)) ? 1 : 0;\n        }\n    };\n\n    auto greedyLocalScore = [&](int p, uint8_t stCand) -> int {\n        int i = p / N, j = p % N;\n        uint8_t mCand = sideMask[stCand];\n\n        int sc = 0;\n        // border match score: only active-active is good\n        auto evalSide = [&](int side, int ni, int nj, int oppSide) {\n            bool a = (mCand >> side) & 1;\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                if (a) sc -= 6; // boundary leak\n                return;\n            }\n            int q = ni * N + nj;\n            bool b = (curMask[q] >> oppSide) & 1;\n            if (a && b) sc += 5;\n            else if (a != b) sc -= 5;\n            // both inactive: 0\n        };\n\n        evalSide(0, i, j - 1, 2);\n        evalSide(1, i - 1, j, 3);\n        evalSide(2, i, j + 1, 0);\n        evalSide(3, i + 1, j, 1);\n\n        // internal pairing potential:\n        // prefer pairing that connects \"continuable\" sides together.\n        int c[4] = { cont(p,0), cont(p,1), cont(p,2), cont(p,3) };\n        int ps = 0;\n        for (int k = 0; k < pairCnt[stCand]; k++) {\n            int a = pairs[stCand][k][0], b = pairs[stCand][k][1];\n            ps += c[a] * c[b];\n        }\n        sc += ps * 3;\n\n        return sc;\n    };\n\n    vector<int> order(TILES);\n    iota(order.begin(), order.end(), 0);\n\n    for (int sweep = 0; sweep < 8; sweep++) {\n        for (int i = TILES - 1; i > 0; i--) {\n            int j = (int)(rng.nextU64() % (uint64_t)(i + 1));\n            swap(order[i], order[j]);\n        }\n        for (int idx = 0; idx < TILES; idx++) {\n            int p = order[idx];\n            int bestSc = INT_MIN;\n            uint8_t bestDelta = 0;\n            uint8_t base = curState[p];\n            for (uint8_t dlt = 0; dlt < 4; dlt++) {\n                uint8_t stCand = rotStep[base][dlt];\n                int sc = greedyLocalScore(p, stCand);\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestDelta = dlt;\n                }\n            }\n            if (bestDelta != 0) {\n                curRot[p] = (uint8_t)((curRot[p] + bestDelta) & 3);\n                curState[p] = rotStep[curState[p]][bestDelta];\n                curMask[p] = sideMask[curState[p]];\n            }\n        }\n    }\n\n    // Evaluation buffers\n    static int degArr[PORTS];\n    static int nb1[PORTS];\n    static int nb2[PORTS];\n    static uint8_t vis[PORTS];\n    static int stackBuf[PORTS];\n\n    auto addEdge = [&](int u, int v) {\n        int du = degArr[u]++;\n        if (du == 0) nb1[u] = v;\n        else nb2[u] = v;\n\n        int dv = degArr[v]++;\n        if (dv == 0) nb1[v] = u;\n        else nb2[v] = u;\n    };\n\n    auto evaluate = [&]() -> EvalResult {\n        memset(degArr, 0, sizeof(degArr));\n        memset(nb1, 0xFF, sizeof(nb1)); // -1\n        memset(nb2, 0xFF, sizeof(nb2));\n        memset(vis, 0, sizeof(vis));\n\n        // internal edges\n        for (int p = 0; p < TILES; p++) {\n            int base = p * 4;\n            uint8_t st = curState[p];\n            for (int k = 0; k < pairCnt[st]; k++) {\n                int a = pairs[st][k][0];\n                int b = pairs[st][k][1];\n                addEdge(base + a, base + b);\n            }\n        }\n\n        // external edges\n        int matchedEdges = 0;\n        // horizontal\n        for (int i = 0; i < N; i++) {\n            int row = i * N;\n            for (int j = 0; j < N - 1; j++) {\n                int p = row + j;\n                int q = p + 1;\n                if ((curMask[p] & (1u << 2)) && (curMask[q] & (1u << 0))) {\n                    addEdge(p * 4 + 2, q * 4 + 0);\n                    matchedEdges++;\n                }\n            }\n        }\n        // vertical\n        for (int i = 0; i < N - 1; i++) {\n            int row = i * N;\n            int row2 = (i + 1) * N;\n            for (int j = 0; j < N; j++) {\n                int p = row + j;\n                int q = row2 + j;\n                if ((curMask[p] & (1u << 3)) && (curMask[q] & (1u << 1))) {\n                    addEdge(p * 4 + 3, q * 4 + 1);\n                    matchedEdges++;\n                }\n            }\n        }\n\n        int openEnds = 0;\n        for (int u = 0; u < PORTS; u++) if (degArr[u] == 1) openEnds++;\n\n        int L1 = 0, L2 = 0;\n        int loopCount = 0;\n        int compCount = 0;\n        int largestCompLen = 0;\n        long long sumCompLenSq = 0;\n\n        for (int s = 0; s < PORTS; s++) {\n            if (degArr[s] == 0 || vis[s]) continue;\n            compCount++;\n\n            int top = 0;\n            stackBuf[top++] = s;\n            vis[s] = 1;\n\n            int compSize = 0;\n            bool isCycle = true;\n\n            while (top) {\n                int x = stackBuf[--top];\n                compSize++;\n                if (degArr[x] != 2) isCycle = false;\n\n                int a = nb1[x], b = nb2[x];\n                if (a != -1 && !vis[a]) { vis[a] = 1; stackBuf[top++] = a; }\n                if (b != -1 && !vis[b]) { vis[b] = 1; stackBuf[top++] = b; }\n            }\n\n            int compLen = compSize / 2; // moves\n            largestCompLen = max(largestCompLen, compLen);\n            sumCompLenSq += 1LL * compLen * compLen;\n\n            if (isCycle) {\n                loopCount++;\n                if (compLen > L1) { L2 = L1; L1 = compLen; }\n                else if (compLen > L2) { L2 = compLen; }\n            }\n        }\n\n        long long base = (loopCount >= 2) ? 1LL * L1 * L2 : 0LL;\n\n        // Energy:\n        // - if >=2 loops exist: focus on product, but discourage too many loops\n        // - if <2: grow large components (easy to close later) and reduce fragmentation\n        double energy;\n        if (loopCount >= 2) {\n            energy = base * 200.0\n                   + (L1 + L2) * 50.0\n                   + largestCompLen * 5.0\n                   + sumCompLenSq * 0.002\n                   - openEnds * 2.0\n                   - max(0, loopCount - 2) * 500.0;\n        } else if (loopCount == 1) {\n            energy = L1 * 60.0\n                   + largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 6000.0;\n        } else {\n            energy = largestCompLen * 6.0\n                   + sumCompLenSq * 0.003\n                   + matchedEdges * 1.0\n                   - openEnds * 2.0\n                   - compCount * 3.0\n                   - 12000.0;\n        }\n\n        return EvalResult{base, L1, L2, loopCount, compCount, matchedEdges, openEnds,\n                          largestCompLen, sumCompLenSq, energy};\n    };\n\n    EvalResult curEval = evaluate();\n    long long bestBase = curEval.baseScore;\n    int bestTie = curEval.L1 + curEval.L2;\n    vector<uint8_t> bestRot = curRot;\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.93;\n\n    // SA temperature (energy scale is now larger)\n    const double T0 = 12000.0;\n    const double T1 = 150.0;\n\n    struct Backup {\n        int p;\n        uint8_t rot, st, mask;\n    };\n\n    auto applyDelta = [&](int p, uint8_t delta) {\n        if ((delta & 3) == 0) return;\n        curRot[p] = (uint8_t)((curRot[p] + delta) & 3);\n        curState[p] = rotStep[curState[p]][delta & 3];\n        curMask[p] = sideMask[curState[p]];\n    };\n\n    long long iter = 0;\n    while (true) {\n        iter++;\n        if ((iter & 1023) == 0) {\n            double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (sec >= TL) break;\n        }\n\n        // move type\n        int r = (int)(rng.nextU64() % 1000);\n\n        vector<int> ps;\n        vector<uint8_t> deltas;\n\n        if (r < 850) {\n            // single tile (bias to 4/5 tiles sometimes)\n            int p;\n            if (!pairTiles.empty() && rng.nextDouble() < 0.45) {\n                p = pairTiles[rng.nextInt(0, (int)pairTiles.size() - 1)];\n            } else {\n                p = (int)(rng.nextU64() % TILES);\n            }\n            uint8_t delta = (uint8_t)(1 + (rng.nextU32() % 3));\n            uint8_t newS = rotStep[curState[p]][delta];\n            if (newS == curState[p]) { delta = 1; }\n            ps = {p};\n            deltas = {delta};\n        } else if (r < 950) {\n            // 2x2 move\n            int i = rng.nextInt(0, N - 2);\n            int j = rng.nextInt(0, N - 2);\n            int p0 = i * N + j;\n            ps = {p0, p0 + 1, p0 + N, p0 + N + 1};\n            deltas.resize(4);\n            int nonzero = 0;\n            for (int k = 0; k < 4; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,3)] = 1;\n        } else {\n            // 1x3 or 3x1 move\n            bool horiz = (rng.nextU32() & 1);\n            if (horiz) {\n                int i = rng.nextInt(0, N - 1);\n                int j = rng.nextInt(0, N - 3);\n                int p0 = i * N + j;\n                ps = {p0, p0 + 1, p0 + 2};\n            } else {\n                int i = rng.nextInt(0, N - 3);\n                int j = rng.nextInt(0, N - 1);\n                int p0 = i * N + j;\n                ps = {p0, p0 + N, p0 + 2 * N};\n            }\n            deltas.resize(3);\n            int nonzero = 0;\n            for (int k = 0; k < 3; k++) {\n                deltas[k] = (uint8_t)(rng.nextU32() % 4);\n                if (deltas[k]) nonzero++;\n            }\n            if (!nonzero) deltas[rng.nextInt(0,2)] = 1;\n        }\n\n        // backup and apply\n        vector<Backup> backups;\n        backups.reserve(ps.size());\n        for (int idx = 0; idx < (int)ps.size(); idx++) {\n            int p = ps[idx];\n            backups.push_back(Backup{p, curRot[p], curState[p], curMask[p]});\n            applyDelta(p, deltas[idx]);\n        }\n\n        EvalResult nxtEval = evaluate();\n\n        double sec = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n        double t = min(1.0, sec / TL);\n        double Temp = T0 * pow(T1 / T0, t);\n\n        double diff = nxtEval.energy - curEval.energy;\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else {\n            double prob = exp(diff / Temp);\n            accept = (rng.nextDouble() < prob);\n        }\n\n        if (accept) {\n            curEval = nxtEval;\n            // best by true score, tie by L1+L2\n            int tie = nxtEval.L1 + nxtEval.L2;\n            if (nxtEval.baseScore > bestBase || (nxtEval.baseScore == bestBase && tie > bestTie)) {\n                bestBase = nxtEval.baseScore;\n                bestTie = tie;\n                bestRot = curRot;\n            }\n        } else {\n            // revert\n            for (auto &b : backups) {\n                curRot[b.p] = b.rot;\n                curState[b.p] = b.st;\n                curMask[b.p] = b.mask;\n            }\n        }\n    }\n\n    // output best\n    string out;\n    out.reserve(TILES);\n    for (int p = 0; p < TILES; p++) out.push_back(char('0' + (bestRot[p] & 3)));\n    cout << out << \"\\n\";\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); }\n    int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n};\n\nstatic inline int hexval(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nstruct UF {\n    int p[110], sz[110];\n    void init(int n) { for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1; }\n    int find(int a) {\n        while (p[a] != a) { p[a] = p[p[a]]; a = p[a]; }\n        return a;\n    }\n    void unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a; sz[a] += sz[b];\n    }\n};\n\nstruct Board {\n    array<uint8_t, 100> a{};\n};\n\nstruct EvalRes {\n    int lt = 0;     // largestTree\n    int ba = 0;     // bestAlmost\n    long long obj = LLONG_MIN;\n};\n\nstruct BaseState {\n    Board b;\n    int blank = -1;\n    uint64_t h = 0;\n    string prefix; // moves from initial to reach this state\n};\n\nstruct RunResult {\n    int bestS = 0;\n    long long bestObj = LLONG_MIN;\n    string bestAns;\n    BaseState bestState; // snapshot at bestAns\n};\n\nstruct Elite {\n    BaseState st;\n    int bestS = 0;\n    long long bestObj = LLONG_MIN;\n};\n\nstruct EvalCache {\n    struct Entry {\n        uint64_t key = 0; // stores h+1, 0 means empty\n        int lt = 0, ba = 0;\n        long long obj = 0;\n    };\n    int capPow = 18; // 2^18 = 262144\n    int cap = 1 << 18;\n    int mask = (1 << 18) - 1;\n    vector<Entry> tab;\n\n    EvalCache() : tab(1 << 18) {}\n\n    inline int idx(uint64_t k) const {\n        // multiplicative hash to spread bits\n        return (int)((k * 11400714819323198485ull) & (uint64_t)mask);\n    }\n\n    bool get(uint64_t h, EvalRes &out) const {\n        uint64_t k = h + 1;\n        int i = idx(k);\n        for (int t = 0; t < 16; t++) {\n            const auto &e = tab[(i + t) & mask];\n            if (e.key == 0) return false;\n            if (e.key == k) {\n                out.lt = e.lt;\n                out.ba = e.ba;\n                out.obj = e.obj;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    void set(uint64_t h, const EvalRes &val) {\n        uint64_t k = h + 1;\n        int i = idx(k);\n        int firstEmpty = -1;\n        for (int t = 0; t < 16; t++) {\n            int p = (i + t) & mask;\n            auto &e = tab[p];\n            if (e.key == k) {\n                e.lt = val.lt; e.ba = val.ba; e.obj = val.obj;\n                return;\n            }\n            if (e.key == 0 && firstEmpty == -1) firstEmpty = p;\n        }\n        if (firstEmpty != -1) {\n            auto &e = tab[firstEmpty];\n            e.key = k;\n            e.lt = val.lt; e.ba = val.ba; e.obj = val.obj;\n        } else {\n            // replace the first slot (rare). heuristic cache so OK.\n            auto &e = tab[i];\n            e.key = k;\n            e.lt = val.lt; e.ba = val.ba; e.obj = val.obj;\n        }\n    }\n};\n\nstruct Solver {\n    int N, T, NN, V;\n    Board initB;\n    int initBlank;\n\n    // blank moves: U D L R\n    const int dr[4] = {-1, +1, 0, 0};\n    const int dc[4] = {0, 0, -1, +1};\n    const char dch[4] = {'U','D','L','R'};\n    const int opp[4] = {1,0,3,2};\n\n    int moveCnt[110];\n    int moveList[110][4];\n    int toPos[110][4];\n\n    int rightNb[110], downNb[110];\n    uint8_t outMask[110];\n    uint8_t pop4tab[16];\n\n    int edgeU[256];\n    int eidx = 0;\n\n    uint64_t zob[110][16];\n\n    EvalCache cache;\n\n    void precompute() {\n        pop4tab[0] = 0;\n        for (int x = 1; x < 16; x++) pop4tab[x] = pop4tab[x >> 1] + (x & 1);\n\n        for (int pos = 0; pos < NN; pos++) {\n            int r = pos / N, c = pos % N;\n            int k = 0;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                    moveList[pos][k++] = d;\n                    toPos[pos][d] = nr * N + nc;\n                } else {\n                    toPos[pos][d] = -1;\n                }\n            }\n            moveCnt[pos] = k;\n\n            rightNb[pos] = (c + 1 < N) ? pos + 1 : -1;\n            downNb[pos]  = (r + 1 < N) ? pos + N : -1;\n\n            uint8_t m = 0;\n            if (c == 0) m |= 1;\n            if (r == 0) m |= 2;\n            if (c == N - 1) m |= 4;\n            if (r == N - 1) m |= 8;\n            outMask[pos] = m;\n        }\n    }\n\n    void init_zobrist() {\n        XorShift64 rng(1234567891234567ULL ^ (uint64_t)N * 1000003ULL);\n        for (int i = 0; i < NN; i++) for (int v = 0; v < 16; v++) zob[i][v] = rng.next_u64();\n    }\n\n    uint64_t calc_hash(const Board &b) const {\n        uint64_t h = 0;\n        for (int i = 0; i < NN; i++) h ^= zob[i][(int)b.a[i]];\n        return h;\n    }\n\n    inline uint64_t swap_hash(uint64_t h, int p, int q, uint8_t vp, uint8_t vq) const {\n        h ^= zob[p][vp]; h ^= zob[q][vq];\n        h ^= zob[p][vq]; h ^= zob[q][vp];\n        return h;\n    }\n\n    inline void apply_move(Board &b, int &blank, uint64_t &h, int d) const {\n        int nb = toPos[blank][d];\n        uint8_t v0 = b.a[blank], v1 = b.a[nb];\n        h = swap_hash(h, blank, nb, v0, v1);\n        swap(b.a[blank], b.a[nb]);\n        blank = nb;\n    }\n\n    EvalRes eval_full(const Board &b) {\n        UF uf;\n        uf.init(NN);\n\n        int edgesTotal = 0, borderOut = 0, mismatch = 0;\n        eidx = 0;\n\n        for (int u = 0; u < NN; u++) {\n            uint8_t tu = b.a[u];\n            if (tu == 0) continue;\n\n            borderOut += pop4tab[(tu & outMask[u]) & 0xF];\n\n            int rv = rightNb[u];\n            if (rv != -1) {\n                uint8_t tv = b.a[rv];\n                bool ar = (tu & 4);\n                bool bl = (tv & 1);\n                bool matched = (tv != 0 && ar && bl);\n                if (ar && !matched) mismatch++;\n                if (tv != 0 && bl && !ar) mismatch++;\n                if (matched) {\n                    uf.unite(u, rv);\n                    edgeU[eidx++] = u;\n                    edgesTotal++;\n                }\n            }\n            int dv = downNb[u];\n            if (dv != -1) {\n                uint8_t tv = b.a[dv];\n                bool ad = (tu & 8);\n                bool bu = (tv & 2);\n                bool matched = (tv != 0 && ad && bu);\n                if (ad && !matched) mismatch++;\n                if (tv != 0 && bu && !ad) mismatch++;\n                if (matched) {\n                    uf.unite(u, dv);\n                    edgeU[eidx++] = u;\n                    edgesTotal++;\n                }\n            }\n        }\n\n        static int vcnt[110], ecnt[110];\n        for (int i = 0; i < NN; i++) vcnt[i] = ecnt[i] = 0;\n        for (int i = 0; i < NN; i++) if (b.a[i] != 0) vcnt[uf.find(i)]++;\n        for (int k = 0; k < eidx; k++) ecnt[uf.find(edgeU[k])]++;\n\n        int largestTree = 0, bestAlmost = 0, cycleSurplus = 0, cyclicLargest = 0;\n        long long treeMass = 0;\n\n        for (int i = 0; i < NN; i++) {\n            int Vc = vcnt[i];\n            if (!Vc) continue;\n            int Ec = ecnt[i];\n            int extra = max(0, Ec - (Vc - 1));\n            cycleSurplus += extra;\n            if (extra > 0) cyclicLargest = max(cyclicLargest, Vc);\n            else {\n                largestTree = max(largestTree, Vc);\n                treeMass += 1LL * Vc * Vc;\n            }\n            bestAlmost = max(bestAlmost, Vc - 10 * extra);\n        }\n\n        long long obj = 0;\n        obj += 1000000000LL * largestTree;\n        obj +=   20000000LL * bestAlmost;\n        obj +=       5000LL * treeMass;\n        obj +=     200000LL * edgesTotal;\n        obj -=   50000000LL * cyclicLargest;\n        obj -=   20000000LL * cycleSurplus;\n        obj -=     500000LL * borderOut;\n        obj -=      20000LL * mismatch;\n\n        EvalRes r;\n        r.lt = largestTree;\n        r.ba = bestAlmost;\n        r.obj = obj;\n        return r;\n    }\n\n    inline EvalRes eval_cached(const Board &b, uint64_t h) {\n        EvalRes r;\n        if (cache.get(h, r)) return r;\n        r = eval_full(b);\n        cache.set(h, r);\n        return r;\n    }\n\n    BaseState move_blank_to(int tr, int tc, const BaseState &src) const {\n        BaseState bs = src;\n        int r = bs.blank / N, c = bs.blank % N;\n        while (r < tr) { apply_move(bs.b, bs.blank, bs.h, 1); bs.prefix.push_back('D'); r++; }\n        while (r > tr) { apply_move(bs.b, bs.blank, bs.h, 0); bs.prefix.push_back('U'); r--; }\n        while (c < tc) { apply_move(bs.b, bs.blank, bs.h, 3); bs.prefix.push_back('R'); c++; }\n        while (c > tc) { apply_move(bs.b, bs.blank, bs.h, 2); bs.prefix.push_back('L'); c--; }\n        if ((int)bs.prefix.size() > T) bs.prefix.resize(T);\n        return bs;\n    }\n\n    // elite compare: maximize (bestS, bestObj), tie-break shorter prefix\n    static inline bool eliteBetter(const Elite &a, const Elite &b) {\n        if (a.bestS != b.bestS) return a.bestS > b.bestS;\n        if (a.bestObj != b.bestObj) return a.bestObj > b.bestObj;\n        return a.st.prefix.size() < b.st.prefix.size();\n    }\n\n    void add_elite(vector<Elite> &elites, const BaseState &st, int bestS, long long bestObj) {\n        if ((int)st.prefix.size() > T - 80) return;\n        // dedupe by hash\n        for (auto &e : elites) {\n            if (e.st.h == st.h) {\n                Elite cand{st, bestS, bestObj};\n                if (eliteBetter(cand, e)) e = std::move(cand);\n                goto SORT_TRIM;\n            }\n        }\n        elites.push_back(Elite{st, bestS, bestObj});\n    SORT_TRIM:\n        sort(elites.begin(), elites.end(), [&](const Elite &x, const Elite &y){ return eliteBetter(x,y); });\n        if ((int)elites.size() > 6) elites.resize(6);\n    }\n\n    int pick_elite_index(const vector<Elite> &elites, XorShift64 &rng) const {\n        int m = (int)elites.size();\n        if (m <= 1) return 0;\n        double r = rng.next_double();\n        if (r < 0.55) return 0;\n        if (m >= 2 && r < 0.80) return 1;\n        if (m >= 3 && r < 0.92) return 2;\n        if (m >= 4 && r < 0.97) return 3;\n        if (m >= 5 && r < 0.99) return 4;\n        return min(m - 1, 5);\n    }\n\n    // warmType: 0 none, 1 normal, 2 micro(<=4)\n    RunResult run_once(const BaseState &base, XorShift64 &rng, double time_frac, int warmType) {\n        RunResult rr;\n\n        Board b = base.b;\n        int blank = base.blank;\n        uint64_t h = base.h;\n\n        int rem = T - (int)base.prefix.size();\n        if (rem < 0) rem = 0;\n\n        string path;\n        path.reserve(rem);\n\n        EvalRes cur = eval_cached(b, h);\n\n        int bestS = cur.lt;\n        long long bestObj = cur.obj;\n        int bestLen = 0;\n\n        // snapshot at best\n        Board bestBoard = b;\n        int bestBlank = blank;\n        uint64_t bestHash = h;\n\n        auto update_best = [&](const EvalRes &m, int len) {\n            if (m.lt > bestS || (m.lt == bestS && m.obj > bestObj)) {\n                bestS = m.lt;\n                bestObj = m.obj;\n                bestLen = len;\n                bestBoard = b;\n                bestBlank = blank;\n                bestHash = h;\n            }\n        };\n\n        // recent hash buffer\n        const int REC = 48;\n        uint64_t recent[REC];\n        int rsz = 0, rptr = 0;\n        auto push_recent = [&](uint64_t hh) {\n            if (rsz < REC) recent[rsz++] = hh;\n            else { recent[rptr] = hh; rptr = (rptr + 1) % REC; }\n        };\n        auto in_recent = [&](uint64_t hh)->bool{\n            for (int i = 0; i < rsz; i++) if (recent[i] == hh) return true;\n            return false;\n        };\n        push_recent(h);\n\n        int prevd = -1;\n\n        // warm-up\n        if (warmType != 0) {\n            int warmMax = (warmType == 1) ? min(rem, (N * N) / 3 + N) : min(rem, 4);\n            int warm = rng.next_int(0, warmMax);\n            for (int w = 0; w < warm; w++) {\n                int cand[4], cc = 0;\n                for (int i = 0; i < moveCnt[blank]; i++) cand[cc++] = moveList[blank][i];\n                if (prevd != -1 && cc >= 2 && rng.next_double() < 0.85) {\n                    int rev = opp[prevd];\n                    int nc = 0;\n                    for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                    if (nc) cc = nc;\n                }\n                int d = cand[rng.next_int(0, cc - 1)];\n                apply_move(b, blank, h, d);\n                path.push_back(dch[d]);\n                prevd = d;\n                cur = eval_cached(b, h);\n                push_recent(h);\n                update_best(cur, (int)path.size());\n            }\n        }\n\n        // epsilon schedule\n        double eps0 = 0.33 - 0.10 * time_frac;\n        double eps1 = 0.06;\n        eps0 = min(0.55, max(0.10, eps0));\n        eps1 = min(0.20, max(0.02, eps1));\n        if (warmType == 0) { eps0 *= 0.60; eps1 *= 0.60; }\n        else if (warmType == 2) { eps0 *= 0.85; eps1 *= 0.85; }\n\n        int topK = (N == 10 ? 3 : 2);\n\n        int baseLimit = 520 + 50 * (N - 6);\n        int highLimit = 900 + 80 * (N - 6);\n        int noImp = 0;\n        int noImpLimit = baseLimit + rng.next_int(0, 220);\n\n        const long long LOOP_PENALTY = 800000LL;\n\n        for (int step = (int)path.size(); step < rem; step++) {\n            if (bestS * 4 >= V * 3) noImpLimit = max(noImpLimit, highLimit);\n\n            double eps = eps0 + (eps1 - eps0) * (double)step / max(1, rem - 1);\n\n            int cand[4], cc = 0;\n            for (int i = 0; i < moveCnt[blank]; i++) cand[cc++] = moveList[blank][i];\n            if (prevd != -1 && cc >= 2 && rng.next_double() < 0.90) {\n                int rev = opp[prevd];\n                int nc = 0;\n                for (int i = 0; i < cc; i++) if (cand[i] != rev) cand[nc++] = cand[i];\n                if (nc) cc = nc;\n            }\n\n            struct CandInfo { int d; EvalRes m1; long long score1; long long score; uint64_t h1; };\n            CandInfo info[4];\n\n            for (int i = 0; i < cc; i++) {\n                int d = cand[i];\n                int nb = toPos[blank][d];\n                uint64_t h1 = swap_hash(h, blank, nb, b.a[blank], b.a[nb]);\n\n                int savedBlank = blank;\n                uint64_t savedHash = h;\n                apply_move(b, blank, h, d);\n\n                EvalRes m1 = eval_cached(b, h);\n\n                // revert\n                swap(b.a[savedBlank], b.a[blank]);\n                blank = savedBlank;\n                h = savedHash;\n\n                long long sc1 = m1.obj;\n                bool improves = (m1.lt > cur.lt) || (m1.lt == cur.lt && m1.ba > cur.ba);\n                if (!improves && in_recent(h1)) sc1 -= LOOP_PENALTY;\n\n                info[i] = {d, m1, sc1, sc1, h1};\n            }\n\n            int ord[4];\n            iota(ord, ord + cc, 0);\n            sort(ord, ord + cc, [&](int a, int b){ return info[a].score1 > info[b].score1; });\n\n            // depth-2 lookahead\n            for (int t = 0; t < min(topK, cc); t++) {\n                int i = ord[t];\n                int d1 = info[i].d;\n\n                int savedBlank1 = blank;\n                uint64_t savedHash1 = h;\n                apply_move(b, blank, h, d1);\n\n                long long best2 = LLONG_MIN;\n                int mc2 = moveCnt[blank];\n                for (int j = 0; j < mc2; j++) {\n                    int d2 = moveList[blank][j];\n                    if (mc2 >= 2 && d2 == opp[d1]) continue;\n\n                    int savedBlank2 = blank;\n                    uint64_t savedHash2 = h;\n                    apply_move(b, blank, h, d2);\n\n                    EvalRes m2 = eval_cached(b, h);\n                    best2 = max(best2, m2.obj);\n\n                    // revert d2\n                    swap(b.a[savedBlank2], b.a[blank]);\n                    blank = savedBlank2;\n                    h = savedHash2;\n                }\n\n                // revert d1\n                swap(b.a[savedBlank1], b.a[blank]);\n                blank = savedBlank1;\n                h = savedHash1;\n\n                if (best2 != LLONG_MIN) info[i].score = info[i].score1 + best2 / 10;\n            }\n\n            int choose = 0;\n            if (rng.next_double() < eps) choose = rng.next_int(0, cc - 1);\n            else {\n                long long bestScore = LLONG_MIN;\n                int bestI = 0;\n                for (int i = 0; i < cc; i++) {\n                    long long sc = info[i].score + (long long)(rng.next_u64() & 1023ULL);\n                    if (sc > bestScore) { bestScore = sc; bestI = i; }\n                }\n                choose = bestI;\n            }\n\n            int d = info[choose].d;\n            apply_move(b, blank, h, d);\n            path.push_back(dch[d]);\n            prevd = d;\n            cur = info[choose].m1;\n            push_recent(h);\n\n            int oldBestS = bestS;\n            long long oldBestObj = bestObj;\n            update_best(cur, (int)path.size());\n\n            if (bestS == oldBestS && bestObj == oldBestObj) noImp++;\n            else noImp = 0;\n\n            if (bestS == V) { bestLen = (int)path.size(); break; }\n            if (noImp > noImpLimit) break;\n        }\n\n        rr.bestS = bestS;\n        rr.bestObj = bestObj;\n        rr.bestAns = base.prefix + path.substr(0, bestLen);\n\n        rr.bestState.b = bestBoard;\n        rr.bestState.blank = bestBlank;\n        rr.bestState.h = bestHash;\n        rr.bestState.prefix = rr.bestAns;\n        if ((int)rr.bestState.prefix.size() > T) rr.bestState.prefix.resize(T);\n        if ((int)rr.bestAns.size() > T) rr.bestAns.resize(T);\n\n        return rr;\n    }\n\n    string solve() {\n        NN = N * N;\n        V = NN - 1;\n        precompute();\n        init_zobrist();\n\n        XorShift64 rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        BaseState baseInit;\n        baseInit.b = initB;\n        baseInit.blank = initBlank;\n        baseInit.prefix.clear();\n        baseInit.h = calc_hash(baseInit.b);\n\n        BaseState baseBR = move_blank_to(N - 1, N - 1, baseInit);\n\n        // initial best\n        EvalRes e0 = eval_cached(baseInit.b, baseInit.h);\n        int globalBestS = e0.lt;\n        long long globalBestObj = e0.obj;\n        string globalBestAns = \"\";\n        BaseState globalBestState = baseInit;\n\n        vector<Elite> elites;\n        add_elite(elites, globalBestState, globalBestS, globalBestObj);\n\n        auto st = chrono::high_resolution_clock::now();\n        const double TL = 2.85;\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n            if (elapsed >= TL) break;\n            double frac = elapsed / TL;\n\n            double q = (V > 0) ? (double)globalBestS / (double)V : 0.0;\n            double pElite = min(0.62, max(0.06, 0.06 + 0.26 * frac + 0.24 * q));\n            double pBR = 0.40 + 0.20 * frac;\n\n            const BaseState *basePtr = nullptr;\n            int warmType = 1;\n\n            bool canElite = !elites.empty() && (int)elites[0].st.prefix.size() <= T - 120;\n            double r = rng.next_double();\n\n            if (canElite && r < pElite) {\n                int ei = pick_elite_index(elites, rng);\n                basePtr = &elites[ei].st;\n                warmType = (rng.next_double() < 0.22 ? 2 : 0);\n            } else {\n                basePtr = (rng.next_double() < pBR) ? &baseBR : &baseInit;\n                warmType = 1;\n            }\n\n            RunResult rr = run_once(*basePtr, rng, frac, warmType);\n\n            if (rr.bestS > globalBestS || (rr.bestS == globalBestS && rr.bestObj > globalBestObj)) {\n                globalBestS = rr.bestS;\n                globalBestObj = rr.bestObj;\n                globalBestAns = rr.bestAns;\n                globalBestState = rr.bestState;\n                add_elite(elites, globalBestState, globalBestS, globalBestObj);\n            } else {\n                if (rr.bestS >= globalBestS - 1 && rng.next_double() < 0.12) {\n                    add_elite(elites, rr.bestState, rr.bestS, rr.bestObj);\n                }\n            }\n\n            if (globalBestS == V) break;\n        }\n\n        if ((int)globalBestAns.size() > T) globalBestAns.resize(T);\n        return globalBestAns;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.T;\n    solver.NN = solver.N * solver.N;\n    solver.T = solver.T;\n    solver.initBlank = -1;\n\n    for (int i = 0; i < solver.N; i++) {\n        string s; cin >> s;\n        for (int j = 0; j < solver.N; j++) {\n            int v = hexval(s[j]);\n            solver.initB.a[i * solver.N + j] = (uint8_t)v;\n            if (v == 0) solver.initBlank = i * solver.N + j;\n        }\n    }\n\n    cout << solver.solve() << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\n#include <boost/unordered/unordered_flat_map.hpp>\n\nusing namespace std;\n\nstatic constexpr int R = 10000;\nstatic constexpr long long LEN = 100000000LL;     // 1e8\nstatic constexpr double U_INACTIVE = R + 4000.0;  // |u| > R => line doesn't intersect the cake\n\n// ---------------- RNG ----------------\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t nextU32() { return (uint32_t)nextU64(); }\n    inline double uniform01() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double uniform(double lo, double hi) { return lo + (hi - lo) * uniform01(); }\n    inline int uniformInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextU32() % (uint32_t)(hi - lo + 1));\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n// ---------------- Geometry / signature ----------------\nstruct Point { int x, y; };\n\nstruct Line {\n    double theta; // [0, pi)\n    double u;     // signed distance along normal\n    long long px, py, qx, qy; // endpoints\n};\n\nstruct Key {\n    uint64_t lo = 0, hi = 0; // up to 128 lines\n    bool operator==(Key const& o) const noexcept { return lo == o.lo && hi == o.hi; }\n};\n\nstruct KeyHash {\n    size_t operator()(Key const& k) const noexcept {\n        uint64_t h = k.lo ^ splitmix64(k.hi + 0x9e3779b97f4a7c15ULL);\n        return (size_t)splitmix64(h);\n    }\n};\n\nstatic inline int getBit(const Key& k, int idx) {\n    if (idx < 64) return (int)((k.lo >> idx) & 1ULL);\n    return (int)((k.hi >> (idx - 64)) & 1ULL);\n}\nstatic inline void setBit(Key& k, int idx) {\n    if (idx < 64) k.lo |= (1ULL << idx);\n    else k.hi |= (1ULL << (idx - 64));\n}\nstatic inline void toggleBit(Key& k, int idx) {\n    if (idx < 64) k.lo ^= (1ULL << idx);\n    else k.hi ^= (1ULL << (idx - 64));\n}\n\nstatic inline double wrapTheta(double th) {\n    const double PI = acos(-1.0);\n    while (th < 0) th += PI;\n    while (th >= PI) th -= PI;\n    return th;\n}\n\nstatic inline Line buildLine(double theta, double u) {\n    double cs = cos(theta), sn = sin(theta);\n    double tx = -sn, ty = cs;\n    double cx = u * cs, cy = u * sn;\n\n    long double px = (long double)cx + (long double)LEN * (long double)tx;\n    long double py = (long double)cy + (long double)LEN * (long double)ty;\n    long double qx = (long double)cx - (long double)LEN * (long double)tx;\n    long double qy = (long double)cy - (long double)LEN * (long double)ty;\n\n    Line L;\n    L.theta = theta;\n    L.u = u;\n    L.px = llround(px);\n    L.py = llround(py);\n    L.qx = llround(qx);\n    L.qy = llround(qy);\n    if (L.px == L.qx && L.py == L.qy) L.qx += 1;\n    return L;\n}\n\n// exact side test by integer cross product\n// 1 if cross>0, 0 if cross<0, -1 if cross==0 (strawberry disappears)\nstatic inline int sideBit(const Line& L, const Point& p) {\n    __int128 dx = (__int128)L.qx - (__int128)L.px;\n    __int128 dy = (__int128)L.qy - (__int128)L.py;\n    __int128 ax = (__int128)p.x - (__int128)L.px;\n    __int128 ay = (__int128)p.y - (__int128)L.py;\n    __int128 cr = dx * ay - dy * ax;\n    if (cr > 0) return 1;\n    if (cr < 0) return 0;\n    return -1;\n}\n\nstatic inline bool isInactive(const Line& L) { return fabs(L.u) > (double)R + 1.0; }\n\n// ---------------- State ----------------\nstruct State {\n    int N = 0;\n    int L = 0;\n    vector<Point> pts;\n    vector<Line> lines;\n    vector<Key> sig;\n    boost::unordered_flat_map<Key, int, KeyHash> mp;\n\n    array<int, 11> a{};\n    array<int, 11> b{}; // pieces with exactly d (1..10)\n    long long excess = 0;   // sum max(0,c-10)\n    long long excess2 = 0;  // sum (max(0,c-10))^2\n    int goodPieces = 0;     // regions with 1..10\n\n    void clearCounts() {\n        mp.clear();\n        b.fill(0);\n        excess = excess2 = 0;\n        goodPieces = 0;\n    }\n\n    static inline long long ex(int c) { return (c <= 10) ? 0LL : (long long)(c - 10); }\n    static inline long long ex2(int c) {\n        if (c <= 10) return 0LL;\n        long long e = (long long)(c - 10);\n        return e * e;\n    }\n\n    inline void updateMetrics(int oldC, int newC) {\n        if (1 <= oldC && oldC <= 10) { b[oldC]--; goodPieces--; }\n        if (1 <= newC && newC <= 10) { b[newC]++; goodPieces++; }\n        excess -= ex(oldC);  excess += ex(newC);\n        excess2 -= ex2(oldC); excess2 += ex2(newC);\n    }\n\n    inline void incRegion(const Key& k) {\n        auto it = mp.find(k);\n        if (it == mp.end()) {\n            updateMetrics(0, 1);\n            mp.emplace(k, 1);\n        } else {\n            int oldC = it->second, newC = oldC + 1;\n            updateMetrics(oldC, newC);\n            it->second = newC;\n        }\n    }\n    inline void decRegion(const Key& k) {\n        auto it = mp.find(k);\n        int oldC = it->second, newC = oldC - 1;\n        updateMetrics(oldC, newC);\n        if (newC == 0) mp.erase(it);\n        else it->second = newC;\n    }\n\n    inline int distributed() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], b[d]);\n        return s;\n    }\n\n    inline long long deficit2() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - b[d]);\n            s += 1LL * def * def;\n        }\n        return s;\n    }\n\n    inline long long overWeighted() const {\n        long long s = 0;\n        for (int d = 1; d <= 10; d++) {\n            int over = max(0, b[d] - a[d]);\n            long long w = (12 - d);\n            s += 1LL * over * w * w;\n        }\n        return s;\n    }\n\n    inline long long secondaryScore() const {\n        long long def2 = deficit2();\n        long long ovW = overWeighted();\n        long long S = 0;\n        S += 1LL * goodPieces * 80;\n        S -= 1LL * excess2 * 3;\n        S -= 1LL * excess * 160;\n        S -= 1LL * def2 * 780;\n        S -= 1LL * ovW * 115;\n        return S;\n    }\n\n    bool buildInitialSignatures() {\n        sig.assign(N, Key{0, 0});\n        clearCounts();\n        mp.reserve((size_t)N * 2 + 64);\n\n        for (int i = 0; i < L; i++) {\n            for (int j = 0; j < N; j++) {\n                int sb = sideBit(lines[i], pts[j]);\n                if (sb == -1) return false;\n                if (sb == 1) setBit(sig[j], i);\n            }\n        }\n        for (int j = 0; j < N; j++) incRegion(sig[j]);\n        return true;\n    }\n\n    // replace one line; rollback on invalid\n    bool applyReplaceLine(int idx, const Line& newLine,\n                          vector<int>& changedIdx, vector<Key>& oldSig) {\n        changedIdx.clear();\n        oldSig.clear();\n        changedIdx.reserve(256);\n        oldSig.reserve(256);\n\n        for (int j = 0; j < N; j++) {\n            int nb = sideBit(newLine, pts[j]);\n            if (nb == -1) {\n                for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n                    int pj = changedIdx[t];\n                    Key os = oldSig[t];\n                    Key cs = sig[pj];\n                    decRegion(cs);\n                    incRegion(os);\n                    sig[pj] = os;\n                }\n                changedIdx.clear();\n                oldSig.clear();\n                return false;\n            }\n            int ob = getBit(sig[j], idx);\n            if (nb == ob) continue;\n\n            changedIdx.push_back(j);\n            oldSig.push_back(sig[j]);\n\n            Key ns = sig[j];\n            toggleBit(ns, idx);\n            decRegion(sig[j]);\n            incRegion(ns);\n            sig[j] = ns;\n        }\n        return true;\n    }\n\n    void rollbackReplaceLine(const vector<int>& changedIdx, const vector<Key>& oldSig) {\n        for (int t = (int)changedIdx.size() - 1; t >= 0; t--) {\n            int j = changedIdx[t];\n            Key os = oldSig[t];\n            Key cs = sig[j];\n            decRegion(cs);\n            incRegion(os);\n            sig[j] = os;\n        }\n    }\n};\n\n// ---------------- Timer ----------------\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsedSec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// ---------------- Helpers ----------------\nstatic Line randomActiveLineAnchored(RNG& rng, const vector<Point>& pts, double theta, double noiseU) {\n    double cs = cos(theta), sn = sin(theta);\n    const Point& p = pts[rng.uniformInt(0, (int)pts.size() - 1)];\n    double proj = cs * (double)p.x + sn * (double)p.y;\n    double u = proj + rng.uniform(-noiseU, noiseU);\n    double lim = R * 0.98;\n    u = max(-lim, min(lim, u));\n    return buildLine(theta, u);\n}\n\n// choose sign of inactive u to match as many current bits as possible (fewer flips -> faster / gentler)\nstatic Line inactiveLineMatched(const State& st, int idx, RNG& rng) {\n    double theta = st.lines[idx].theta;\n    Line Lpos = buildLine(theta, +U_INACTIVE);\n    Line Lneg = buildLine(theta, -U_INACTIVE);\n\n    int matchPos = 0, matchNeg = 0;\n    int samples = min(st.N, 80);\n    for (int t = 0; t < samples; t++) {\n        int j = (st.N == samples) ? t : rng.uniformInt(0, st.N - 1);\n        int ob = getBit(st.sig[j], idx);\n        int nbp = sideBit(Lpos, st.pts[j]);\n        int nbn = sideBit(Lneg, st.pts[j]);\n        if (nbp == ob) matchPos++;\n        if (nbn == ob) matchNeg++;\n    }\n    return (matchPos >= matchNeg) ? Lpos : Lneg;\n}\n\nstatic int nearestLineIndex(const vector<Line>& lines, const Point& p) {\n    int best = 0;\n    double bestAbs = 1e100;\n    for (int i = 0; i < (int)lines.size(); i++) {\n        double cs = cos(lines[i].theta), sn = sin(lines[i].theta);\n        double dist = cs * (double)p.x + sn * (double)p.y - lines[i].u;\n        double ad = fabs(dist);\n        if (ad < bestAbs) { bestAbs = ad; best = i; }\n    }\n    return best;\n}\n\nstatic int pickInactiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (isInactive(lines[i])) return i;\n    }\n    for (int i = 0; i < L; i++) if (isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\nstatic int pickActiveIndex(RNG& rng, const vector<Line>& lines) {\n    int L = (int)lines.size();\n    for (int t = 0; t < 12; t++) {\n        int i = rng.uniformInt(0, L - 1);\n        if (!isInactive(lines[i])) return i;\n    }\n    for (int i = 0; i < L; i++) if (!isInactive(lines[i])) return i;\n    return rng.uniformInt(0, L - 1);\n}\n\n// Generate a quantile split line for a given region (key) and target size d.\n// Returns false if region too small.\nstatic bool generateQuantileSplit(const State& st, const Key& key, int regionSize, int targetD,\n                                  RNG& rng, Line& outLine) {\n    if (regionSize <= targetD || regionSize < 6) return false;\n\n    // collect region members\n    vector<int> idxs;\n    idxs.reserve(regionSize);\n    for (int j = 0; j < st.N; j++) if (st.sig[j] == key) idxs.push_back(j);\n    if ((int)idxs.size() < 6) return false;\n\n    // sample up to 220 points to reduce cost / noise\n    int M = min<int>(220, (int)idxs.size());\n    if ((int)idxs.size() > M) {\n        for (int t = 0; t < M; t++) {\n            int r = rng.uniformInt(t, (int)idxs.size() - 1);\n            swap(idxs[t], idxs[r]);\n        }\n        idxs.resize(M);\n    }\n\n    const double PI = acos(-1.0);\n    int ANG = 12;\n    double bestTheta = rng.uniform(0.0, PI);\n    double bestU = 0.0;\n    double bestGap = -1.0;\n\n    // desired fraction\n    double frac = (double)targetD / (double)regionSize;\n    int kpos = (int)llround(frac * (double)(M - 1));\n    kpos = max(1, min(M - 1, kpos));\n\n    vector<double> proj;\n    proj.reserve(M);\n\n    for (int t = 0; t < ANG; t++) {\n        double theta = rng.uniform(0.0, PI);\n        double cs = cos(theta), sn = sin(theta);\n\n        proj.clear();\n        for (int j : idxs) proj.push_back(cs * (double)st.pts[j].x + sn * (double)st.pts[j].y);\n        sort(proj.begin(), proj.end());\n\n        double a1 = proj[kpos - 1];\n        double a2 = proj[kpos];\n        double gap = a2 - a1;\n        if (gap > bestGap) {\n            bestGap = gap;\n            bestTheta = theta;\n            bestU = 0.5 * (a1 + a2);\n        }\n    }\n\n    double lim = R * 0.98;\n    bestU = max(-lim, min(lim, bestU));\n    outLine = buildLine(bestTheta, bestU);\n    return true;\n}\n\n// Best-improvement postprocess: adaptively merge (deactivate) or split (activate) for histogram matching.\nstatic vector<Line> hillclimbPostprocess(const vector<Line>& inputLines,\n                                        const vector<Point>& pts,\n                                        const array<int,11>& a,\n                                        RNG& rng,\n                                        double timeBudgetSec) {\n    const int L = (int)inputLines.size();\n    State st;\n    st.N = (int)pts.size();\n    st.L = L;\n    st.pts = pts;\n    st.a = a;\n    st.lines = inputLines;\n    if (!st.buildInitialSignatures()) return inputLines;\n\n    int curD = st.distributed();\n    long long curS = st.secondaryScore();\n\n    vector<int> changed;\n    vector<Key> oldSig;\n\n    auto t0 = chrono::steady_clock::now();\n    int iter = 0;\n\n    while (true) {\n        double el = chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n        if (el > timeBudgetSec) break;\n        if (++iter > 20) break;\n\n        // compute deficits\n        int defSmall = 0, defLarge = 0;\n        array<int,11> def{};\n        for (int d = 1; d <= 10; d++) {\n            def[d] = max(0, st.a[d] - st.b[d]);\n            if (d <= 4) defSmall += def[d];\n            if (d >= 8) defLarge += def[d];\n        }\n\n        bool wantMerge = (defLarge > defSmall); // heuristic\n        bool improved = false;\n\n        // --- Try best merge by deactivation ---\n        if (wantMerge) {\n            int bestIdx = -1;\n            Line bestLine;\n            int bestD = curD;\n            long long bestS = curS;\n\n            // evaluate all active lines\n            for (int i = 0; i < L; i++) {\n                if (isInactive(st.lines[i])) continue;\n\n                Line cand = inactiveLineMatched(st, i, rng);\n\n                if (!st.applyReplaceLine(i, cand, changed, oldSig)) continue;\n                int nd = st.distributed();\n                long long ns = st.secondaryScore();\n\n                bool better = (nd > bestD) || (nd == bestD && ns > bestS);\n                st.rollbackReplaceLine(changed, oldSig);\n\n                if (better) {\n                    bestD = nd; bestS = ns;\n                    bestIdx = i; bestLine = cand;\n                }\n            }\n\n            if (bestIdx != -1 && (bestD > curD || (bestD == curD && bestS > curS))) {\n                // apply\n                st.applyReplaceLine(bestIdx, bestLine, changed, oldSig);\n                st.lines[bestIdx] = bestLine;\n                curD = bestD; curS = bestS;\n                improved = true;\n            }\n        }\n\n        // --- Try best split by activation (or modifying an inactive line) ---\n        if (!improved) {\n            // pick a target size with largest deficit (weighted towards medium/large a bit)\n            int targetD = 1;\n            long long bestNeed = -1;\n            for (int d = 1; d <= 10; d++) {\n                long long need = max(0, st.a[d] - st.b[d]);\n                if (need == 0) continue;\n                long long score = need * 100 + d * 8;\n                if (score > bestNeed) { bestNeed = score; targetD = d; }\n            }\n\n            // If no deficits, still try to reduce secondary penalties a bit by splitting large regions\n            bool haveDef = (bestNeed >= 0);\n\n            // find a focus region that can be split to produce targetD\n            int bestJ = -1;\n            int bestCnt = 0;\n            Key bestKey;\n            for (int t = 0; t < 90; t++) {\n                int j = rng.uniformInt(0, st.N - 1);\n                auto it = st.mp.find(st.sig[j]);\n                int c = (it == st.mp.end()) ? 0 : it->second;\n                if (haveDef) {\n                    if (c <= targetD) continue;\n                } else {\n                    if (c <= 10) continue;\n                }\n                if (c > bestCnt) {\n                    bestCnt = c;\n                    bestJ = j;\n                    bestKey = st.sig[j];\n                }\n            }\n\n            if (bestJ != -1) {\n                int useIdx = pickInactiveIndex(rng, st.lines);\n                int bestIdx = -1;\n                Line bestLine;\n                int bestD = curD;\n                long long bestS = curS;\n\n                // try several candidate split lines, keep best\n                for (int tr = 0; tr < 14; tr++) {\n                    Line cand;\n                    int desired = haveDef ? min(targetD, bestCnt - 1) : min(10, bestCnt - 1);\n                    desired = max(1, desired);\n                    if (!generateQuantileSplit(st, bestKey, bestCnt, desired, rng, cand)) continue;\n\n                    if (!st.applyReplaceLine(useIdx, cand, changed, oldSig)) continue;\n                    int nd = st.distributed();\n                    long long ns = st.secondaryScore();\n                    bool better = (nd > bestD) || (nd == bestD && ns > bestS);\n                    st.rollbackReplaceLine(changed, oldSig);\n\n                    if (better) {\n                        bestD = nd; bestS = ns;\n                        bestIdx = useIdx; bestLine = cand;\n                    }\n                }\n\n                if (bestIdx != -1 && (bestD > curD || (bestD == curD && bestS > curS))) {\n                    st.applyReplaceLine(bestIdx, bestLine, changed, oldSig);\n                    st.lines[bestIdx] = bestLine;\n                    curD = bestD; curS = bestS;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break; // local optimum for this postprocess\n    }\n\n    return st.lines;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, K;\n    cin >> N >> K;\n    array<int, 11> a{};\n    for (int d = 1; d <= 10; d++) cin >> a[d];\n    vector<Point> pts(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    Timer timer;\n    RNG rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    const double TIME_LIMIT = 2.93;\n    const int L = 100;\n    const int RESTARTS = 4;\n    const double PI = acos(-1.0);\n\n    int globalBestD = -1;\n    long long globalBestS = LLONG_MIN;\n    vector<Line> globalBestLines;\n\n    for (int rs = 0; rs < RESTARTS; rs++) {\n        double now = timer.elapsedSec();\n        if (now >= TIME_LIMIT) break;\n        double rem = TIME_LIMIT - now;\n        double budget = rem / (double)(RESTARTS - rs);\n\n        State st;\n        st.N = N; st.L = L; st.pts = pts; st.a = a;\n        st.lines.resize(L);\n\n        // init: moderate number of active lines; rest inactive.\n        int initActive = 52 + rs * 10; // diversified\n        initActive = max(35, min(92, initActive));\n\n        for (int i = 0; i < L; i++) {\n            double thetaBase = PI * (i + 0.5) / (double)L;\n            double theta = wrapTheta(thetaBase + rng.uniform(-0.03, 0.03));\n            if (i < initActive) st.lines[i] = randomActiveLineAnchored(rng, pts, theta, 1300.0);\n            else st.lines[i] = buildLine(theta, (rng.uniform01() < 0.5 ? +U_INACTIVE : -U_INACTIVE));\n        }\n\n        if (!st.buildInitialSignatures()) continue;\n\n        int curD = st.distributed();\n        long long curS = st.secondaryScore();\n        int bestD = curD;\n        long long bestS = curS;\n        vector<Line> bestLines = st.lines;\n\n        vector<int> changedIdx;\n        vector<Key> oldSig;\n\n        auto start = chrono::steady_clock::now();\n\n        while (true) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            if (elapsed >= budget) break;\n            double prog = elapsed / budget;\n\n            // two-temperature acceptance\n            double Td0 = 2.6, Td1 = 0.12;\n            double Ts0 = 260000.0, Ts1 = 9000.0;\n            double Td = Td0 * (1.0 - prog) + Td1 * prog;\n            double Ts = Ts0 * (1.0 - prog) + Ts1 * prog;\n\n            // compute deficit trend\n            int defSmall = 0, defLarge = 0;\n            for (int d = 1; d <= 4; d++) defSmall += max(0, st.a[d] - st.b[d]);\n            for (int d = 8; d <= 10; d++) defLarge += max(0, st.a[d] - st.b[d]);\n\n            // pick focus: region with large count\n            int focusJ = rng.uniformInt(0, N - 1);\n            int focusCnt = 0;\n            Key focusKey;\n\n            if (rng.uniform01() < 0.55) {\n                int bestJ = focusJ, bestCnt = 0;\n                for (int t = 0; t < 20; t++) {\n                    int j = rng.uniformInt(0, N - 1);\n                    auto it = st.mp.find(st.sig[j]);\n                    int c = (it == st.mp.end()) ? 0 : it->second;\n                    if (c > bestCnt) { bestCnt = c; bestJ = j; }\n                }\n                focusJ = bestJ;\n            }\n            focusKey = st.sig[focusJ];\n            {\n                auto it = st.mp.find(focusKey);\n                focusCnt = (it == st.mp.end()) ? 0 : it->second;\n            }\n\n            bool focusMove = (focusCnt > 10 && rng.uniform01() < 0.75);\n\n            // adaptive move weights\n            double pToggle = 0.10 + (defLarge > defSmall ? 0.05 : -0.02);\n            pToggle = max(0.05, min(0.18, pToggle));\n            double pQuant = 0.24 + (defSmall > defLarge ? 0.07 : -0.03);\n            pQuant = max(0.16, min(0.35, pQuant));\n            double pResample = 0.26;\n            double pPerturb = 1.0 - (pToggle + pQuant + pResample);\n            if (pPerturb < 0.15) { pPerturb = 0.15; pResample = 1.0 - (pToggle + pQuant + pPerturb); }\n\n            double r = rng.uniform01();\n\n            int idx = -1;\n            Line cand;\n\n            // (A) toggle activate/deactivate\n            if (r < pToggle) {\n                if (defLarge > defSmall) idx = pickActiveIndex(rng, st.lines);\n                else idx = pickInactiveIndex(rng, st.lines);\n\n                Line old = st.lines[idx];\n                if (isInactive(old)) {\n                    // activate near focus\n                    double theta = old.theta;\n                    double cs = cos(theta), sn = sin(theta);\n                    const Point& p = st.pts[focusJ];\n                    double projp = cs * (double)p.x + sn * (double)p.y;\n                    double u = projp + rng.uniform(-750.0, 750.0);\n                    double lim = R * 0.98;\n                    u = max(-lim, min(lim, u));\n                    cand = buildLine(theta, u);\n                } else {\n                    cand = inactiveLineMatched(st, idx, rng);\n                }\n            }\n            // (B) quantile split\n            else if (r < pToggle + pQuant && focusCnt >= 6) {\n                // prefer using inactive slot to add split\n                if (rng.uniform01() < 0.70) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                // choose target size with largest deficit feasible\n                int tMax = min(10, focusCnt - 1);\n                int targetD = 1;\n                long long bestNeed = -1;\n                for (int d = 1; d <= tMax; d++) {\n                    long long need = max(0, st.a[d] - st.b[d]);\n                    long long sc = need * 100 + d * 6;\n                    if (sc > bestNeed) { bestNeed = sc; targetD = d; }\n                }\n                if (bestNeed < 0) targetD = min(10, focusCnt - 1);\n\n                if (!generateQuantileSplit(st, focusKey, focusCnt, targetD, rng, cand)) {\n                    double theta = rng.uniform(0.0, PI);\n                    cand = randomActiveLineAnchored(rng, pts, theta, 1200.0);\n                }\n            }\n            // (C) resample active line near focus\n            else if (r < pToggle + pQuant + pResample || focusMove) {\n                if (defSmall >= defLarge && rng.uniform01() < 0.65) idx = pickInactiveIndex(rng, st.lines);\n                else idx = nearestLineIndex(st.lines, st.pts[focusJ]);\n\n                double theta = rng.uniform(0.0, PI);\n                double cs = cos(theta), sn = sin(theta);\n                const Point& p = st.pts[focusJ];\n                double projp = cs * (double)p.x + sn * (double)p.y;\n                double u = projp + rng.uniform(-850.0, 850.0);\n                double lim = R * 0.98;\n                u = max(-lim, min(lim, u));\n                cand = buildLine(theta, u);\n            }\n            // (D) perturb\n            else {\n                idx = rng.uniformInt(0, L - 1);\n                Line old = st.lines[idx];\n                cand = old;\n                double angleScale = 0.55 * (1.0 - prog) + 0.010;\n                double uScale = 5400.0 * (1.0 - prog) + 110.0;\n                cand.theta = wrapTheta(cand.theta + rng.uniform(-angleScale, angleScale));\n                cand.u += rng.uniform(-uScale, uScale);\n                cand.u = max(-U_INACTIVE, min(U_INACTIVE, cand.u));\n                cand = buildLine(cand.theta, cand.u);\n            }\n\n            int oldD = curD;\n            long long oldS = curS;\n\n            if (!st.applyReplaceLine(idx, cand, changedIdx, oldSig)) continue;\n\n            int newD = st.distributed();\n            long long newS = st.secondaryScore();\n\n            bool accept = false;\n            if (newD > oldD) accept = true;\n            else if (newD < oldD) {\n                double prob = exp((double)(newD - oldD) / Td);\n                if (rng.uniform01() < prob) accept = true;\n            } else {\n                long long dS = newS - oldS;\n                if (dS >= 0) accept = true;\n                else {\n                    double x = (double)dS / Ts;\n                    if (x > -60) {\n                        double prob = exp(x);\n                        if (rng.uniform01() < prob) accept = true;\n                    }\n                }\n            }\n\n            if (accept) {\n                st.lines[idx] = cand;\n                curD = newD;\n                curS = newS;\n                if (curD > bestD || (curD == bestD && curS > bestS)) {\n                    bestD = curD;\n                    bestS = curS;\n                    bestLines = st.lines;\n                }\n            } else {\n                st.rollbackReplaceLine(changedIdx, oldSig);\n            }\n        }\n\n        // Postprocess: best-improvement hillclimb (merge/split)\n        double remAll = TIME_LIMIT - timer.elapsedSec();\n        double postBudget = min(0.22, max(0.05, remAll * 0.30));\n        bestLines = hillclimbPostprocess(bestLines, pts, a, rng, postBudget);\n\n        // Evaluate postprocessed\n        {\n            State tmp;\n            tmp.N = N; tmp.L = L; tmp.pts = pts; tmp.a = a; tmp.lines = bestLines;\n            if (tmp.buildInitialSignatures()) {\n                bestD = tmp.distributed();\n                bestS = tmp.secondaryScore();\n            }\n        }\n\n        if (bestD > globalBestD || (bestD == globalBestD && bestS > globalBestS)) {\n            globalBestD = bestD;\n            globalBestS = bestS;\n            globalBestLines = bestLines;\n        }\n    }\n\n    if (globalBestLines.empty()) {\n        cout << 0 << \"\\n\";\n        return 0;\n    }\n    cout << (int)globalBestLines.size() << \"\\n\";\n    for (auto& Lx : globalBestLines) {\n        cout << Lx.px << \" \" << Lx.py << \" \" << Lx.qx << \" \" << Lx.qy << \"\\n\";\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    explicit XorShift(uint64_t seed = 0) { x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstatic inline uint64_t maskRange64(int l, int r) {\n    if (l > r) return 0;\n    uint64_t left = (~0ULL) << l;\n    uint64_t right = (r == 63) ? ~0ULL : ((1ULL << (r + 1)) - 1ULL);\n    return left & right;\n}\n\nstruct Bits128 {\n    uint64_t lo = 0, hi = 0;\n    inline void set(int idx) { (idx < 64) ? (lo |= 1ULL << idx) : (hi |= 1ULL << (idx - 64)); }\n    inline void reset(int idx) { (idx < 64) ? (lo &= ~(1ULL << idx)) : (hi &= ~(1ULL << (idx - 64))); }\n    inline bool any() const { return lo || hi; }\n    inline Bits128 operator&(const Bits128& o) const { return Bits128{lo & o.lo, hi & o.hi}; }\n\n    inline bool anyInRange(int l, int r) const { // inclusive\n        if (l > r) return false;\n        uint64_t mlo = 0, mhi = 0;\n        if (l < 64) {\n            int rr = min(r, 63);\n            mlo = maskRange64(l, rr);\n        }\n        if (r >= 64) {\n            int ll = max(l, 64) - 64;\n            int rr = r - 64;\n            mhi = maskRange64(ll, rr);\n        }\n        return (lo & mlo) || (hi & mhi);\n    }\n};\n\nstruct Point { int x, y; };\n\nstruct Move {\n    Point p1, p2, p3, p4;\n    bool isAxis = true;\n    int x1=0, y1=0, x2=0, y2=0; // axis\n    int u1=0, u2=0, v1=0, v2=0; // diag params (v is vIdx)\n    int per = 0;\n    double val = -1e100;\n};\n\nstatic inline double linterp(double a, double b, double t) { return a + (b - a) * t; }\n\nstruct Params {\n    int topP = 240;\n    int midP = 1050;\n    int randP = 70;\n\n    // tie-break noise (small)\n    double noise = 0.012;\n\n    // normal mode (progressive)\n    double alphaStart = 0.58, alphaEnd = 0.28;   // perimeter\n    double alpha2Start = 0.0008, alpha2End = 0.0;// quadratic perimeter\n    double betaStart  = 1.90, betaEnd  = 0.55;   // sum connectivity\n    double psiStart   = 0.00, psiEnd   = 0.00;   // balanced connectivity (min-based), NEW but can be 0\n    double deltaStart = 0.90, deltaEnd = 0.25;   // capacity\n    double gammaStart = 32.0, gammaEnd = 8.0;    // tightness penalty\n\n    // epsilon-greedy\n    double epsStart = 0.05, epsEnd = 0.00;\n\n    // fill fallback\n    double fillWcoef = 0.18;\n    double fillAlpha = 0.90;\n    double fillAlpha2 = 0.0014;\n    double fillBeta  = 1.05;\n    double fillPsi   = 0.00;\n    double fillDelta = 1.20;\n    double fillGamma = 40.0;\n    double fillEps   = 0.02;\n};\n\nstruct Coefs {\n    double wcoef, alpha, alpha2, beta, psi, delta, gamma, eps;\n};\n\nstruct State {\n    int N;\n    int shiftV;\n    int U, V;\n\n    array<uint64_t, 61> dotRow{};\n    array<uint64_t, 61> dotCol{};\n\n    vector<Bits128> diagVdots;\n    vector<Bits128> antiUdots;\n\n    array<uint64_t, 61> hUsed{};\n    array<uint64_t, 61> vUsed{};\n    vector<uint64_t> d1SegUsed;\n    vector<uint64_t> d2SegUsed;\n\n    array<uint8_t, 61> hCnt{};\n    array<uint8_t, 61> vCnt{};\n    vector<uint8_t> d1Cnt;\n    vector<uint8_t> d2Cnt;\n\n    array<uint8_t, 61> rowCnt{};\n    array<uint8_t, 61> colCnt{};\n    vector<uint8_t> diagVCnt;\n    vector<uint8_t> antiUCnt;\n\n    int dots = 0;\n    long long sumW = 0;\n\n    State(int N_=0): N(N_) {}\n\n    inline bool hasDot(int x, int y) const { return (dotRow[y] >> x) & 1ULL; }\n\n    inline void addDot(int x, int y) {\n        dotRow[y] |= 1ULL << x;\n        dotCol[x] |= 1ULL << y;\n        rowCnt[y]++; colCnt[x]++;\n        int u = x + y;\n        int vIdx = x - y + shiftV;\n        diagVdots[vIdx].set(u);\n        antiUdots[u].set(vIdx);\n        diagVCnt[vIdx]++; antiUCnt[u]++;\n        dots++;\n    }\n\n    inline bool rowHasDotBetween(int y, int x1, int x2) const {\n        int l = min(x1, x2) + 1;\n        int r = max(x1, x2) - 1;\n        if (l > r) return false;\n        return (dotRow[y] & maskRange64(l, r)) != 0;\n    }\n    inline bool colHasDotBetween(int x, int y1, int y2) const {\n        int l = min(y1, y2) + 1;\n        int r = max(y1, y2) - 1;\n        if (l > r) return false;\n        return (dotCol[x] & maskRange64(l, r)) != 0;\n    }\n\n    inline uint64_t segMaskX(int x1, int x2) const {\n        int l = min(x1, x2);\n        int r = max(x1, x2) - 1;\n        return maskRange64(l, r);\n    }\n    inline uint64_t segMaskY(int y1, int y2) const {\n        int l = min(y1, y2);\n        int r = max(y1, y2) - 1;\n        return maskRange64(l, r);\n    }\n\n    inline void markH(int y, uint64_t m) {\n        uint64_t add = m & ~hUsed[y];\n        hUsed[y] |= m;\n        hCnt[y] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markV(int x, uint64_t m) {\n        uint64_t add = m & ~vUsed[x];\n        vUsed[x] |= m;\n        vCnt[x] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markD1(int vIdx, uint64_t m) {\n        uint64_t add = m & ~d1SegUsed[vIdx];\n        d1SegUsed[vIdx] |= m;\n        d1Cnt[vIdx] += (uint8_t)__builtin_popcountll(add);\n    }\n    inline void markD2(int u, uint64_t m) {\n        uint64_t add = m & ~d2SegUsed[u];\n        d2SegUsed[u] |= m;\n        d2Cnt[u] += (uint8_t)__builtin_popcountll(add);\n    }\n\n    inline int lenD1(int vIdx) const {\n        int d = vIdx - shiftV;\n        return N - abs(d);\n    }\n    inline int lenD2(int u) const {\n        return N - abs(u - (N - 1));\n    }\n    inline int posD1(int vIdx, int x, int y) const {\n        int d = vIdx - shiftV;\n        return (d >= 0) ? y : x;\n    }\n    inline int posD2(int u, int x, int /*y*/) const {\n        int startX = (u < N) ? 0 : (u - (N - 1));\n        return x - startX;\n    }\n\n    inline uint64_t dMaskRange(int posA, int posB) const {\n        int l = min(posA, posB);\n        int r = max(posA, posB) - 1;\n        return (l <= r) ? maskRange64(l, r) : 0ULL;\n    }\n\n    inline bool d1FreeMask(int vIdx, uint64_t m) const { return (d1SegUsed[vIdx] & m) == 0; }\n    inline bool d2FreeMask(int u, uint64_t m) const { return (d2SegUsed[u] & m) == 0; }\n\n    inline Point uvToXY(int u, int vIdx) const {\n        int v = vIdx - shiftV;\n        int x = (u + v) / 2;\n        int y = (u - v) / 2;\n        return {x, y};\n    }\n\n    inline int freeRowSeg(int y) const { return (N - 1) - (int)hCnt[y]; }\n    inline int freeColSeg(int x) const { return (N - 1) - (int)vCnt[x]; }\n    inline int freeD1Seg(int vIdx) const {\n        int seg = max(0, lenD1(vIdx) - 1);\n        return seg - (int)d1Cnt[vIdx];\n    }\n    inline int freeD2Seg(int u) const {\n        int seg = max(0, lenD2(u) - 1);\n        return seg - (int)d2Cnt[u];\n    }\n\n    inline bool canAxisRect(int x1, int y1, int x2, int y2) const {\n        if (x1 == x2 || y1 == y2) return false;\n        if (hasDot(x1, y1)) return false;\n        if (!hasDot(x2, y1) || !hasDot(x2, y2) || !hasDot(x1, y2)) return false;\n\n        if (rowHasDotBetween(y1, x1, x2)) return false;\n        if (rowHasDotBetween(y2, x1, x2)) return false;\n        if (colHasDotBetween(x1, y1, y2)) return false;\n        if (colHasDotBetween(x2, y1, y2)) return false;\n\n        uint64_t hm = segMaskX(x1, x2);\n        if ((hUsed[y1] & hm) || (hUsed[y2] & hm)) return false;\n        uint64_t vm = segMaskY(y1, y2);\n        if ((vUsed[x1] & vm) || (vUsed[x2] & vm)) return false;\n        return true;\n    }\n\n    inline void applyAxisRect(const Move& mv) {\n        uint64_t hm = segMaskX(mv.x1, mv.x2);\n        uint64_t vm = segMaskY(mv.y1, mv.y2);\n        markH(mv.y1, hm);\n        markH(mv.y2, hm);\n        markV(mv.x1, vm);\n        markV(mv.x2, vm);\n        addDot(mv.x1, mv.y1);\n    }\n\n    inline bool canDiagRect(int x1, int y1, int u2, int v2Idx) const {\n        if (hasDot(x1, y1)) return false;\n        int u1 = x1 + y1;\n        int v1Idx = x1 - y1 + shiftV;\n\n        if (diagVdots[v1Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (diagVdots[v2Idx].anyInRange(min(u1, u2) + 1, max(u1, u2) - 1)) return false;\n        if (antiUdots[u1].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n        if (antiUdots[u2].anyInRange(min(v1Idx, v2Idx) + 1, max(v1Idx, v2Idx) - 1)) return false;\n\n        Point p2 = uvToXY(u2, v1Idx);\n        Point p3 = uvToXY(u2, v2Idx);\n        Point p4 = uvToXY(u1, v2Idx);\n\n        auto in = [&](Point p) { return 0 <= p.x && p.x < N && 0 <= p.y && p.y < N; };\n        if (!in(p2) || !in(p3) || !in(p4)) return false;\n        if (!hasDot(p2.x, p2.y) || !hasDot(p3.x, p3.y) || !hasDot(p4.x, p4.y)) return false;\n\n        int uA = u2, uB = u1;\n        int vA = v1Idx, vB = v2Idx;\n\n        uint64_t m1 = dMaskRange(posD1(vA, x1, y1), posD1(vA, p2.x, p2.y));\n        if (!d1FreeMask(vA, m1)) return false;\n        uint64_t m2 = dMaskRange(posD2(uA, p2.x, p2.y), posD2(uA, p3.x, p3.y));\n        if (!d2FreeMask(uA, m2)) return false;\n        uint64_t m3 = dMaskRange(posD1(vB, p3.x, p3.y), posD1(vB, p4.x, p4.y));\n        if (!d1FreeMask(vB, m3)) return false;\n        uint64_t m4 = dMaskRange(posD2(uB, p4.x, p4.y), posD2(uB, x1, y1));\n        if (!d2FreeMask(uB, m4)) return false;\n\n        return true;\n    }\n\n    inline void applyDiagRect(const Move& mv) {\n        Point p2 = uvToXY(mv.u2, mv.v1);\n        Point p3 = uvToXY(mv.u2, mv.v2);\n        Point p4 = uvToXY(mv.u1, mv.v2);\n\n        uint64_t m1 = dMaskRange(posD1(mv.v1, mv.x1, mv.y1), posD1(mv.v1, p2.x, p2.y));\n        uint64_t m2 = dMaskRange(posD2(mv.u2, p2.x, p2.y), posD2(mv.u2, p3.x, p3.y));\n        uint64_t m3 = dMaskRange(posD1(mv.v2, p3.x, p3.y), posD1(mv.v2, p4.x, p4.y));\n        uint64_t m4 = dMaskRange(posD2(mv.u1, p4.x, p4.y), posD2(mv.u1, mv.x1, mv.y1));\n\n        markD1(mv.v1, m1);\n        markD2(mv.u2, m2);\n        markD1(mv.v2, m3);\n        markD2(mv.u1, m4);\n\n        addDot(mv.x1, mv.y1);\n    }\n};\n\nstruct Result {\n    vector<array<int, 8>> ops;\n    long long sumW = -1;\n    int dots = 0;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int c = (N - 1) / 2;\n\n    vector<vector<int>> w(N, vector<int>(N, 0)); // w[x][y]\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) {\n        int dx = x - c, dy = y - c;\n        w[x][y] = dx * dx + dy * dy + 1;\n    }\n\n    vector<Point> initial(M);\n    for (int i = 0; i < M; i++) cin >> initial[i].x >> initial[i].y;\n\n    vector<Point> allPoints;\n    allPoints.reserve(N * N);\n    for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) allPoints.push_back({x, y});\n    sort(allPoints.begin(), allPoints.end(), [&](const Point& a, const Point& b) {\n        int wa = w[a.x][a.y], wb = w[b.x][b.y];\n        if (wa != wb) return wa > wb;\n        if (a.x != b.x) return a.x < b.x;\n        return a.y < b.y;\n    });\n\n    // inv[k] = 1/(k+1)\n    array<double, 64> inv{};\n    for (int i = 0; i < 64; i++) inv[i] = 1.0 / (double)(i + 1);\n\n    auto start = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]() -> double {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - start).count();\n    };\n\n    auto perimeterAxis = [&](int x1, int y1, int x2, int y2) -> int {\n        return 2 * (abs(x2 - x1) + abs(y2 - y1));\n    };\n    auto perimeterDiagParams = [&](int u1, int u2, int v1, int v2) -> int {\n        int a = abs(u2 - u1) / 2;\n        int b = abs(v2 - v1) / 2;\n        return 2 * (a + b);\n    };\n\n    auto runOnce = [&](uint64_t seed, const Params& par) -> Result {\n        XorShift rng(seed);\n\n        State st(N);\n        st.shiftV = N - 1;\n        st.U = 2 * N - 1;\n        st.V = 2 * N - 1;\n\n        st.diagVdots.assign(st.V, Bits128{});\n        st.antiUdots.assign(st.U, Bits128{});\n        st.d1SegUsed.assign(st.V, 0ULL);\n        st.d2SegUsed.assign(st.U, 0ULL);\n        st.d1Cnt.assign(st.V, 0);\n        st.d2Cnt.assign(st.U, 0);\n        st.diagVCnt.assign(st.V, 0);\n        st.antiUCnt.assign(st.U, 0);\n\n        for (auto &x : st.dotRow) x = 0;\n        for (auto &x : st.dotCol) x = 0;\n        for (auto &x : st.hUsed) x = 0;\n        for (auto &x : st.vUsed) x = 0;\n        for (auto &x : st.hCnt) x = 0;\n        for (auto &x : st.vCnt) x = 0;\n        for (auto &x : st.rowCnt) x = 0;\n        for (auto &x : st.colCnt) x = 0;\n\n        st.dots = 0;\n        st.sumW = 0;\n        for (auto p : initial) { st.addDot(p.x, p.y); st.sumW += w[p.x][p.y]; }\n\n        vector<array<int, 8>> ops;\n        ops.reserve(N * N);\n\n        auto collectP1 = [&](int P) {\n            vector<Point> res;\n            res.reserve(P + par.randP);\n            for (const auto& p : allPoints) {\n                if ((int)res.size() >= P) break;\n                if (!st.hasDot(p.x, p.y)) res.push_back(p);\n            }\n            for (int i = 0; i < par.randP; i++) {\n                for (int t = 0; t < 40; t++) {\n                    int x = rng.nextInt(0, N - 1);\n                    int y = rng.nextInt(0, N - 1);\n                    if (!st.hasDot(x, y)) { res.push_back({x, y}); break; }\n                }\n            }\n            return res;\n        };\n\n        auto buildCoefs = [&](bool fillMode) -> Coefs {\n            double progress = (double)ops.size() / (double)max(1, (N * N - M));\n            progress = min(1.0, max(0.0, progress));\n            Coefs cf;\n            if (!fillMode) {\n                cf.wcoef = 1.0;\n                cf.alpha  = linterp(par.alphaStart,  par.alphaEnd,  progress);\n                cf.alpha2 = linterp(par.alpha2Start, par.alpha2End, progress);\n                cf.beta   = linterp(par.betaStart,   par.betaEnd,   progress);\n                cf.psi    = linterp(par.psiStart,    par.psiEnd,    progress);\n                cf.delta  = linterp(par.deltaStart,  par.deltaEnd,  progress);\n                cf.gamma  = linterp(par.gammaStart,  par.gammaEnd,  progress);\n                cf.eps    = linterp(par.epsStart,    par.epsEnd,    progress);\n            } else {\n                cf.wcoef = par.fillWcoef;\n                cf.alpha = par.fillAlpha;\n                cf.alpha2 = par.fillAlpha2;\n                cf.beta = par.fillBeta;\n                cf.psi = par.fillPsi;\n                cf.delta = par.fillDelta;\n                cf.gamma = par.fillGamma;\n                cf.eps = par.fillEps;\n            }\n            return cf;\n        };\n\n        auto evalMove = [&](const Move& mv, const Coefs& cf) -> double {\n            int x1 = mv.x1, y1 = mv.y1;\n            int u1 = x1 + y1;\n            int vIdx = x1 - y1 + st.shiftV;\n\n            int connSum = (int)st.rowCnt[y1] + (int)st.colCnt[x1] + (int)st.diagVCnt[vIdx] + (int)st.antiUCnt[u1];\n\n            // mild balanced connectivity (min-based, always defined)\n            int connBal = min<int>(st.rowCnt[y1], st.colCnt[x1]) + min<int>(st.diagVCnt[vIdx], st.antiUCnt[u1]);\n\n            int cap = 0;\n            double tight = 0.0;\n\n            if (mv.isAxis) {\n                int freeR1 = st.freeRowSeg(mv.y1), freeR2 = st.freeRowSeg(mv.y2);\n                int freeC1 = st.freeColSeg(mv.x1), freeC2 = st.freeColSeg(mv.x2);\n                cap = freeR1 + freeR2 + freeC1 + freeC2;\n\n                int dx = abs(mv.x2 - mv.x1);\n                int dy = abs(mv.y2 - mv.y1);\n                tight = dx * inv[freeR1] + dx * inv[freeR2] + dy * inv[freeC1] + dy * inv[freeC2];\n            } else {\n                int freeV1 = st.freeD1Seg(mv.v1), freeV2 = st.freeD1Seg(mv.v2);\n                int freeU1 = st.freeD2Seg(mv.u1), freeU2 = st.freeD2Seg(mv.u2);\n                cap = freeV1 + freeV2 + freeU1 + freeU2;\n\n                int a = abs(mv.u2 - mv.u1) / 2;\n                int b = abs(mv.v2 - mv.v1) / 2;\n                tight = a * inv[freeV1] + a * inv[freeV2] + b * inv[freeU1] + b * inv[freeU2];\n            }\n\n            double val = 0.0;\n            val += cf.wcoef * (double)w[x1][y1];\n            val += cf.beta * (double)connSum;\n            val += cf.psi * (double)connBal;\n            val += cf.delta * (double)cap;\n            val -= cf.alpha * (double)mv.per;\n            val -= cf.alpha2 * (double)mv.per * (double)mv.per;\n            val -= cf.gamma * tight;\n            val += par.noise * rng.nextDouble();\n            return val;\n        };\n\n        auto findBestMove = [&](Move& chosen, bool fillMode) -> bool {\n            Coefs cf = buildCoefs(fillMode);\n\n            Move best, second;\n            bool hasBest = false, hasSecond = false;\n\n            auto update = [&](Move&& mv) {\n                mv.val = evalMove(mv, cf);\n                if (!hasBest || mv.val > best.val) {\n                    if (hasBest) { second = best; hasSecond = true; }\n                    best = mv; hasBest = true;\n                } else if ((!hasSecond || mv.val > second.val) && mv.val < best.val - 1e-12) {\n                    second = mv; hasSecond = true;\n                }\n            };\n\n            auto enumerate = [&](int P) {\n                auto p1s = collectP1(P);\n                for (const auto& p1 : p1s) {\n                    int x1 = p1.x, y1 = p1.y;\n                    if (st.hasDot(x1, y1)) continue;\n\n                    // axis\n                    uint64_t yMask = st.dotCol[x1];\n                    while (yMask) {\n                        int y2 = __builtin_ctzll(yMask);\n                        yMask &= yMask - 1;\n                        if (y2 == y1) continue;\n\n                        uint64_t inter = st.dotRow[y1] & st.dotRow[y2];\n                        inter &= ~(1ULL << x1);\n                        while (inter) {\n                            int x2 = __builtin_ctzll(inter);\n                            inter &= inter - 1;\n                            if (!st.canAxisRect(x1, y1, x2, y2)) continue;\n\n                            Move mv;\n                            mv.isAxis = true;\n                            mv.p1 = {x1, y1}; mv.p2 = {x2, y1}; mv.p3 = {x2, y2}; mv.p4 = {x1, y2};\n                            mv.x1 = x1; mv.y1 = y1; mv.x2 = x2; mv.y2 = y2;\n                            mv.per = perimeterAxis(x1, y1, x2, y2);\n                            update(std::move(mv));\n                        }\n                    }\n\n                    // diagonal\n                    int u1 = x1 + y1;\n                    int v1Idx = x1 - y1 + st.shiftV;\n\n                    Bits128 vMask = st.antiUdots[u1];\n                    uint64_t vlo = vMask.lo, vhi = vMask.hi;\n\n                    auto handleV2 = [&](int v2Idx) {\n                        if (v2Idx == v1Idx) return;\n                        Bits128 interU = st.diagVdots[v1Idx] & st.diagVdots[v2Idx];\n                        if (u1 < 128) interU.reset(u1);\n                        if (!interU.any()) return;\n\n                        uint64_t ulo = interU.lo, uhi = interU.hi;\n                        auto handleU2 = [&](int u2) {\n                            if (u2 == u1) return;\n                            if (!st.canDiagRect(x1, y1, u2, v2Idx)) return;\n\n                            Point p2 = st.uvToXY(u2, v1Idx);\n                            Point p3 = st.uvToXY(u2, v2Idx);\n                            Point p4 = st.uvToXY(u1, v2Idx);\n\n                            Move mv;\n                            mv.isAxis = false;\n                            mv.p1 = {x1, y1}; mv.p2 = p2; mv.p3 = p3; mv.p4 = p4;\n                            mv.x1 = x1; mv.y1 = y1;\n                            mv.u1 = u1; mv.u2 = u2;\n                            mv.v1 = v1Idx; mv.v2 = v2Idx;\n                            mv.per = perimeterDiagParams(mv.u1, mv.u2, mv.v1, mv.v2);\n                            update(std::move(mv));\n                        };\n\n                        while (ulo) { int b = __builtin_ctzll(ulo); ulo &= ulo - 1; handleU2(b); }\n                        while (uhi) { int b = __builtin_ctzll(uhi); uhi &= uhi - 1; handleU2(64 + b); }\n                    };\n\n                    while (vlo) { int b = __builtin_ctzll(vlo); vlo &= vlo - 1; handleV2(b); }\n                    while (vhi) { int b = __builtin_ctzll(vhi); vhi &= vhi - 1; handleV2(64 + b); }\n                }\n            };\n\n            if (!fillMode) {\n                enumerate(par.topP);\n                if (!hasBest) enumerate(par.midP);\n                if (!hasBest) enumerate(N * N);\n            } else {\n                enumerate(par.midP);\n                if (!hasBest) enumerate(N * N);\n            }\n\n            if (!hasBest) return false;\n            if (hasSecond && rng.nextDouble() < cf.eps) chosen = second;\n            else chosen = best;\n            return true;\n        };\n\n        while (true) {\n            // time guard inside loop body to allow finishing current findBestMove\n            if (chrono::duration<double>(chrono::high_resolution_clock::now() - start).count() > 4.92) break;\n\n            Move mv;\n            if (!findBestMove(mv, false)) {\n                if (!findBestMove(mv, true)) break;\n            }\n\n            if (mv.isAxis) st.applyAxisRect(mv);\n            else st.applyDiagRect(mv);\n\n            st.sumW += w[mv.x1][mv.y1];\n            ops.push_back({mv.p1.x, mv.p1.y, mv.p2.x, mv.p2.y, mv.p3.x, mv.p3.y, mv.p4.x, mv.p4.y});\n        }\n\n        Result res;\n        res.ops = std::move(ops);\n        res.sumW = st.sumW;\n        res.dots = st.dots;\n        return res;\n    };\n\n    // Put BOTH: psi=0 baseline, and psi>0 balanced-connectivity variant\n    vector<Params> plist;\n    {\n        Params p; // baseline (psi=0)\n        p.randP = 70;\n        p.noise = 0.012;\n        p.psiStart = 0.0; p.psiEnd = 0.0; p.fillPsi = 0.0;\n        plist.push_back(p);\n    }\n    {\n        Params p; // balanced connectivity (mild)\n        p.randP = 80;\n        p.noise = 0.013;\n        p.psiStart = 0.45; p.psiEnd = 0.10;\n        p.fillPsi = 0.18;\n        plist.push_back(p);\n    }\n    {\n        Params p; // more exploration in candidate pool, slightly different weights\n        p.topP = 280; p.midP = 1250; p.randP = 90;\n        p.alphaStart = 0.55; p.alphaEnd = 0.26;\n        p.betaStart  = 1.75; p.betaEnd  = 0.50;\n        p.deltaStart = 1.00; p.deltaEnd = 0.28;\n        p.gammaStart = 28.0; p.gammaEnd = 7.0;\n        p.psiStart = 0.35; p.psiEnd = 0.08;\n        p.fillPsi = 0.14;\n        p.noise = 0.014;\n        plist.push_back(p);\n    }\n\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result bestRes;\n    bestRes.sumW = -1;\n\n    int trial = 0;\n    while (elapsedSec() < 4.93) {\n        const Params& par = plist[trial % (int)plist.size()];\n        uint64_t seed = baseSeed + 1000003ULL * (uint64_t)trial;\n        auto res = runOnce(seed, par);\n        if (res.sumW > bestRes.sumW || (res.sumW == bestRes.sumW && res.ops.size() > bestRes.ops.size())) {\n            bestRes = std::move(res);\n        }\n        trial++;\n    }\n\n    cout << bestRes.ops.size() << \"\\n\";\n    for (auto &a : bestRes.ops) {\n        for (int i = 0; i < 8; i++) {\n            if (i) cout << ' ';\n            cout << a[i];\n        }\n        cout << \"\\n\";\n    }\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int M = 100;\n\n// ---------------- RNG ----------------\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n};\n\n// ---------------- Board ----------------\nstruct Board {\n    array<uint8_t, M> a{}; // 0 empty, 1..3 flavors\n    uint8_t empty_cnt = 100;\n\n    // dir: 0=F(up),1=B(down),2=L(left),3=R(right)\n    inline void tilt(int dir) {\n        if (dir == 2) { // L\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0, base = r * N;\n                for (int c = 0; c < N; c++) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = (c < k ? tmp[c] : 0);\n            }\n        } else if (dir == 3) { // R\n            for (int r = 0; r < N; r++) {\n                uint8_t tmp[N];\n                int k = 0, base = r * N;\n                for (int c = N - 1; c >= 0; c--) {\n                    uint8_t v = a[base + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int c = 0; c < N; c++) a[base + c] = 0;\n                for (int i = 0; i < k; i++) a[base + (N - 1 - i)] = tmp[i];\n            }\n        } else if (dir == 0) { // F\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = 0; r < N; r++) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = (r < k ? tmp[r] : 0);\n            }\n        } else { // B\n            for (int c = 0; c < N; c++) {\n                uint8_t tmp[N];\n                int k = 0;\n                for (int r = N - 1; r >= 0; r--) {\n                    uint8_t v = a[r * N + c];\n                    if (v) tmp[k++] = v;\n                }\n                for (int r = 0; r < N; r++) a[r * N + c] = 0;\n                for (int i = 0; i < k; i++) a[(N - 1 - i) * N + c] = tmp[i];\n            }\n        }\n    }\n\n    inline void place_by_p(int p, uint8_t flavor) {\n        int cnt = 0;\n        for (int i = 0; i < M; i++) {\n            if (a[i] == 0) {\n                if (++cnt == p) {\n                    a[i] = flavor;\n                    empty_cnt--;\n                    return;\n                }\n            }\n        }\n    }\n\n    inline void place_random_empty(uint8_t flavor, XorShift64 &rng) {\n        int E = (int)empty_cnt;\n        if (E <= 0) return;\n        int k = rng.next_int(E); // exactly 1 RNG call\n        for (int i = 0; i < M; i++) if (a[i] == 0) {\n            if (k == 0) {\n                a[i] = flavor;\n                empty_cnt--;\n                return;\n            }\n            --k;\n        }\n    }\n};\n\n// ---------------- Precompute ----------------\nstatic array<uint8_t, M> RR{}, CC{};\nstatic array<int, M> rightN{}, downN{};\n\nstatic inline void init_pre() {\n    for (int i = 0; i < M; i++) {\n        int r = i / N, c = i % N;\n        RR[i] = (uint8_t)r;\n        CC[i] = (uint8_t)c;\n        rightN[i] = (c + 1 < N ? i + 1 : -1);\n        downN[i]  = (r + 1 < N ? i + N : -1);\n    }\n}\n\n// ---------------- DSU ----------------\nstatic inline int dsu_find(int x, int *p) {\n    while (p[x] != x) {\n        p[x] = p[p[x]];\n        x = p[x];\n    }\n    return x;\n}\nstatic inline void dsu_unite(int a, int b, int *p, int *sz) {\n    a = dsu_find(a, p);\n    b = dsu_find(b, p);\n    if (a == b) return;\n    if (sz[a] < sz[b]) swap(a, b);\n    p[b] = a;\n    sz[a] += sz[b];\n}\n\nstatic inline long long comp_sq_sum_dsu(const Board &b, int &same_adj, int &diff_adj, int &empty_adj) {\n    int parent[M], sz[M];\n    for (int i = 0; i < M; i++) {\n        parent[i] = i;\n        sz[i] = (b.a[i] ? 1 : 0);\n    }\n    same_adj = diff_adj = empty_adj = 0;\n\n    for (int i = 0; i < M; i++) {\n        int j = rightN[i];\n        if (j != -1) {\n            uint8_t ai = b.a[i], aj = b.a[j];\n            if (!ai && !aj) empty_adj++;\n            else if (ai && aj) {\n                if (ai == aj) { same_adj++; dsu_unite(i, j, parent, sz); }\n                else diff_adj++;\n            }\n        }\n        j = downN[i];\n        if (j != -1) {\n            uint8_t ai = b.a[i], aj = b.a[j];\n            if (!ai && !aj) empty_adj++;\n            else if (ai && aj) {\n                if (ai == aj) { same_adj++; dsu_unite(i, j, parent, sz); }\n                else diff_adj++;\n            }\n        }\n    }\n\n    long long sumsq = 0;\n    for (int i = 0; i < M; i++) if (parent[i] == i && sz[i] > 0) sumsq += 1LL * sz[i] * sz[i];\n    return sumsq;\n}\n\n// ---------------- Shape features ----------------\nstruct ShapeFeat {\n    long long variance = 0;    // candy compactness penalty\n    long long separation = 0;  // centroid separation bonus\n    int empty_corner = 0;      // empties close to some corner (O(1))\n    long long empty_var = 0;   // empty compactness penalty\n};\n\nstatic inline ShapeFeat compute_shape(const Board &b) {\n    long long cnt[4]   = {0,0,0,0};\n    long long sumr[4]  = {0,0,0,0}, sumc[4]  = {0,0,0,0};\n    long long sumr2[4] = {0,0,0,0}, sumc2[4] = {0,0,0,0};\n\n    long long Ec = 0, Esr = 0, Esc = 0, Esr2 = 0, Esc2 = 0;\n\n    for (int i = 0; i < M; i++) {\n        uint8_t v = b.a[i];\n        int r = RR[i], c = CC[i];\n        if (!v) {\n            Ec++;\n            Esr += r; Esc += c;\n            Esr2 += 1LL * r * r;\n            Esc2 += 1LL * c * c;\n            continue;\n        }\n        cnt[v]++;\n        sumr[v] += r; sumc[v] += c;\n        sumr2[v] += 1LL * r * r;\n        sumc2[v] += 1LL * c * c;\n    }\n\n    ShapeFeat ft;\n\n    if (Ec >= 1) {\n        long long dist00 = Esr + Esc;\n        long long dist09 = Esr + (9 * Ec - Esc);\n        long long dist90 = (9 * Ec - Esr) + Esc;\n        long long dist99 = (9 * Ec - Esr) + (9 * Ec - Esc);\n        long long minDist = min(min(dist00, dist09), min(dist90, dist99));\n        ft.empty_corner = (int)(18 * Ec - minDist);\n    }\n\n    if (Ec >= 2) {\n        long long vr = Esr2 * Ec - Esr * Esr;\n        long long vc = Esc2 * Ec - Esc * Esc;\n        ft.empty_var = vr + vc;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        if (cnt[f] <= 1) continue;\n        long long vr = sumr2[f] * cnt[f] - sumr[f] * sumr[f];\n        long long vc = sumc2[f] * cnt[f] - sumc[f] * sumc[f];\n        ft.variance += vr + vc;\n    }\n\n    for (int i = 1; i <= 3; i++) for (int j = i + 1; j <= 3; j++) {\n        if (cnt[i] == 0 || cnt[j] == 0) continue;\n        ft.separation += llabs(sumr[i] * cnt[j] - sumr[j] * cnt[i]);\n        ft.separation += llabs(sumc[i] * cnt[j] - sumc[j] * cnt[i]);\n    }\n\n    return ft;\n}\n\n// ---------------- Evaluation ----------------\nstatic inline long long full_eval(const Board &b) {\n    int filled = 100 - (int)b.empty_cnt;\n    int same_adj, diff_adj, empty_adj;\n    long long cs = comp_sq_sum_dsu(b, same_adj, diff_adj, empty_adj);\n    ShapeFeat sh = compute_shape(b);\n\n    long long wComp = (filled < 30 ? 450 : (filled < 70 ? 1650 : 3700));\n    long long wSame = (filled < 30 ? 120 : (filled < 70 ? 90   : 70));\n    long long wDiff = (filled < 30 ? 200 : (filled < 70 ? 140  : 110));\n    long long wVar  = (filled < 30 ? 3   : (filled < 70 ? 2    : 1));\n    long long wSep  = (filled < 30 ? 6   : (filled < 70 ? 4    : 2));\n    long long wEC   = (filled < 30 ? 95  : (filled < 70 ? 55   : 16));\n    long long wEmpA = 5;\n    long long wEVar = (filled < 30 ? 10  : (filled < 70 ? 7    : 4));\n\n    return cs * wComp\n         + 1LL * same_adj * wSame\n         - 1LL * diff_adj * wDiff\n         - 1LL * sh.variance * wVar\n         + 1LL * sh.separation * wSep\n         + 1LL * sh.empty_corner * wEC\n         + 1LL * empty_adj * wEmpA\n         - (sh.empty_var / 25) * wEVar;\n}\n\n// ---------------- Rollout fast eval ----------------\nstatic inline int fast_eval_rollout(const Board &b) {\n    int same_adj = 0, diff_adj = 0, empty_adj = 0;\n    long long Ec = 0, Esr = 0, Esc = 0, Esr2 = 0, Esc2 = 0;\n\n    for (int i = 0; i < M; i++) {\n        if (b.a[i] == 0) {\n            int r = RR[i], c = CC[i];\n            Ec++;\n            Esr += r; Esc += c;\n            Esr2 += 1LL * r * r;\n            Esc2 += 1LL * c * c;\n        }\n        int j = rightN[i];\n        if (j != -1) {\n            uint8_t a = b.a[i], c = b.a[j];\n            if (!a && !c) empty_adj++;\n            else if (a && c) (a == c ? same_adj++ : diff_adj++);\n        }\n        j = downN[i];\n        if (j != -1) {\n            uint8_t a = b.a[i], c = b.a[j];\n            if (!a && !c) empty_adj++;\n            else if (a && c) (a == c ? same_adj++ : diff_adj++);\n        }\n    }\n\n    long long empty_var = 0;\n    if (Ec >= 2) {\n        long long vr = Esr2 * Ec - Esr * Esr;\n        long long vc = Esc2 * Ec - Esc * Esc;\n        empty_var = vr + vc;\n    }\n\n    int empty_corner = 0;\n    if (Ec >= 1) {\n        long long dist00 = Esr + Esc;\n        long long dist09 = Esr + (9 * Ec - Esc);\n        long long dist90 = (9 * Ec - Esr) + Esc;\n        long long dist99 = (9 * Ec - Esr) + (9 * Ec - Esc);\n        long long minDist = min(min(dist00, dist09), min(dist90, dist99));\n        empty_corner = (int)(18 * Ec - minDist);\n    }\n\n    long long v = 0;\n    v += 150LL * same_adj;\n    v -= 210LL * diff_adj;\n    v += 15LL  * empty_adj;\n    v += 60LL  * empty_corner;\n    v -= 10LL  * (empty_var / 25);\n\n    v = max<long long>(v, (long long)INT_MIN);\n    v = min<long long>(v, (long long)INT_MAX);\n    return (int)v;\n}\n\n// One RNG per step; mostly greedy; only randomize tie / near-tie.\nstatic inline int rollout_policy_neartie(const Board &b, XorShift64 &rng_act) {\n    uint64_t r = rng_act.next_u64(); // exactly 1 RNG call per step\n\n    int val[4];\n    for (int d = 0; d < 4; d++) {\n        Board nb = b;\n        nb.tilt(d);\n        val[d] = fast_eval_rollout(nb);\n    }\n\n    // find best and second best\n    int best = 0;\n    for (int d = 1; d < 4; d++) if (val[d] > val[best]) best = d;\n    int second = (best == 0 ? 1 : 0);\n    for (int d = 0; d < 4; d++) if (d != best) {\n        if (val[d] > val[second]) second = d;\n    }\n\n    int diff = val[best] - val[second];\n\n    // Handle exact ties among best set deterministically but with r-based selection.\n    int bestDirs[4], k = 0;\n    for (int d = 0; d < 4; d++) if (val[d] == val[best]) bestDirs[k++] = d;\n    if (k >= 2) return bestDirs[(int)((r >> 12) % (uint64_t)k)];\n\n    // Near-tie: occasionally pick second to escape brittle greedy paths.\n    // Use r bits; no extra RNG calls.\n    if (diff <= 20) {\n        // 50% choose second\n        return ((r >> 8) & 1ULL) ? second : best;\n    } else if (diff <= 40) {\n        // 25% choose second\n        return (((r >> 8) & 3ULL) == 0ULL) ? second : best;\n    }\n    return best;\n}\n\nstatic inline long long simulate_rollout(Board b, int t_next, int depth,\n                                        const array<uint8_t, 100> &flv,\n                                        XorShift64 &rng_place,\n                                        XorShift64 &rng_act) {\n    for (int step = 0; step < depth && t_next < 100; step++, t_next++) {\n        b.place_random_empty(flv[t_next], rng_place);\n        if (t_next == 99) break;\n        int d = rollout_policy_neartie(b, rng_act);\n        b.tilt(d);\n    }\n    return full_eval(b);\n}\n\nstatic inline char dir_char(int d) {\n    static const char mp[4] = {'F','B','L','R'};\n    return mp[d];\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_pre();\n\n    array<uint8_t, 100> flv{};\n    for (int i = 0; i < 100; i++) {\n        int x; cin >> x;\n        flv[i] = (uint8_t)x;\n    }\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < 100; i++) seed = (seed ^ flv[i]) * 1099511628211ULL;\n    XorShift64 rng(seed);\n\n    Board cur;\n\n    auto t_start = chrono::steady_clock::now();\n    const double TL = 1.992;\n\n    for (int t = 0; t < 100; t++) {\n        int p; cin >> p;\n        cur.place_by_p(p, flv[t]);\n        if (t == 99) break;\n\n        Board candB[4];\n        long double sum[4];\n        int cnt[4];\n\n        for (int d = 0; d < 4; d++) {\n            candB[d] = cur;\n            candB[d].tilt(d);\n            long long v = full_eval(candB[d]);\n            sum[d] = (long double)v;\n            cnt[d] = 1;\n        }\n\n        int remainMoves = 99 - t;\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n        double left = TL - elapsed;\n        if (left < 0) left = 0;\n\n        double base = (remainMoves > 0 ? left / remainMoves : 0.0);\n        double earlyFactor = 1.28 - 0.78 * (double)t / 99.0;\n        double budget = base * earlyFactor * 0.90;\n        budget = min(budget, 0.105);\n        budget = max(budget, 0.0015);\n\n        int remain = 99 - t;\n        int depth = (remain >= 70 ? 8 : (remain >= 40 ? 6 : (remain >= 20 ? 4 : 3)));\n        depth = min(depth, 100 - (t + 1));\n\n        auto avg = [&](int d)->long double { return sum[d] / (long double)cnt[d]; };\n\n        auto move_end = chrono::steady_clock::now() + chrono::duration<double>(budget);\n        auto phase1_end = chrono::steady_clock::now() + chrono::duration<double>(budget * 0.52);\n\n        // Phase 1: sample all 4 with aligned RNG streams\n        while (chrono::steady_clock::now() < phase1_end) {\n            uint64_t s = rng.next_u64();\n            for (int d = 0; d < 4; d++) {\n                XorShift64 rp(s);\n                XorShift64 ra(s ^ 0x9e3779b97f4a7c15ULL);\n                long long v = simulate_rollout(candB[d], t + 1, depth, flv, rp, ra);\n                sum[d] += (long double)v;\n                cnt[d] += 1;\n            }\n        }\n\n        array<int,4> ord = {0,1,2,3};\n        auto recompute_ord = [&]() {\n            sort(ord.begin(), ord.end(), [&](int i, int j){ return avg(i) > avg(j); });\n        };\n        recompute_ord();\n\n        // Phase 2: race among topK, but periodically refresh topK and sometimes sample all4.\n        int iter = 0;\n        while (chrono::steady_clock::now() < move_end) {\n            if ((iter % 8) == 0) recompute_ord();\n\n            long double a2 = avg(ord[1]);\n            long double a3 = avg(ord[2]);\n            long double gap23 = a2 - a3;\n            long double thr = 0.004L * (fabsl(a2) + 1.0L) + 15000.0L;\n            int K = (gap23 < thr ? 3 : 2);\n\n            uint64_t s = rng.next_u64();\n            if ((iter++ % 12) == 0) {\n                for (int d = 0; d < 4; d++) {\n                    XorShift64 rp(s);\n                    XorShift64 ra(s ^ 0x9e3779b97f4a7c15ULL);\n                    long long v = simulate_rollout(candB[d], t + 1, depth, flv, rp, ra);\n                    sum[d] += (long double)v;\n                    cnt[d] += 1;\n                }\n            } else {\n                for (int idx = 0; idx < K; idx++) {\n                    int d = ord[idx];\n                    XorShift64 rp(s);\n                    XorShift64 ra(s ^ 0x9e3779b97f4a7c15ULL);\n                    long long v = simulate_rollout(candB[d], t + 1, depth, flv, rp, ra);\n                    sum[d] += (long double)v;\n                    cnt[d] += 1;\n                }\n            }\n        }\n\n        int bestDir = 0;\n        long double bestVal = -1e300L;\n        for (int d = 0; d < 4; d++) {\n            long double v = avg(d);\n            if (v > bestVal) {\n                bestVal = v;\n                bestDir = d;\n            }\n        }\n\n        cout << dir_char(bestDir) << '\\n' << flush;\n        cur.tilt(bestDir);\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\n#include <csignal>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int lo, int hi) { // inclusive\n        return lo + (int)(next_u64() % (uint64_t)(hi - lo + 1));\n    }\n};\n\nstatic long long C2ll(long long x){ return x*(x-1)/2; }\nstatic long long C3ll(long long x){ return x*(x-1)*(x-2)/6; }\n\n// N<=100 => 2xuint64 bitset\nusing BS = array<uint64_t, 2>;\nstatic inline int pc_and(const BS& a, const BS& b){\n    return __builtin_popcountll(a[0] & b[0]) + __builtin_popcountll(a[1] & b[1]);\n}\nstatic inline int get_bit(const BS& a, int u){\n    if (u < 64) return (a[0] >> u) & 1ULL;\n    return (a[1] >> (u - 64)) & 1ULL;\n}\nstatic inline void set_bit(BS& a, int u){\n    if (u < 64) a[0] |= 1ULL << u;\n    else a[1] |= 1ULL << (u - 64);\n}\nstatic inline void flip_bit(BS& a, int u){\n    if (u < 64) a[0] ^= 1ULL << u;\n    else a[1] ^= 1ULL << (u - 64);\n}\n\nstatic vector<double> binom_pmf(int n, double p) {\n    vector<double> pmf(n+1, 0.0);\n    if (n==0) { pmf[0]=1.0; return pmf; }\n    if (p<=0.0) { pmf[0]=1.0; return pmf; }\n    if (p>=1.0) { pmf[n]=1.0; return pmf; }\n    double q = 1.0 - p;\n    pmf[0] = pow(q, n);\n    double ratio = p / q;\n    for (int k=1;k<=n;k++){\n        pmf[k] = pmf[k-1] * (double)(n-k+1) / (double)k * ratio;\n    }\n    return pmf;\n}\n\nstatic int choose_ms(double eps){\n    if (eps <= 0.15) return 1;\n    if (eps <= 0.25) return 2;\n    if (eps <= 0.33) return 3;\n    return 4;\n}\n\nstatic int chooseN_init(int M, double eps){\n    if (eps <= 0.00) return 13;\n    if (eps <= 0.01) return (M <= 95 ? 13 : 14);\n    if (eps <= 0.02) return 14;\n    if (eps <= 0.05) return 18;\n    if (eps <= 0.10) return 26;\n    if (eps <= 0.15) return 34;\n    if (eps <= 0.20) return 45;\n    if (eps <= 0.25) return 60;\n    if (eps <= 0.30) return 80;\n    if (eps <= 0.32) return 92;\n    return 100;\n}\n\nstruct Part {\n    vector<int> sz;     // clique sizes descending\n    int Pin = 0;        // sum C2\n    long long Tin = 0;  // sum C3\n    long long S2 = 0;   // sum s^2\n    long long S3 = 0;   // sum s^3\n    int B = 0;\n    int mx = 0, mn = 0;\n};\n\nstatic Part make_part(const vector<int>& sz){\n    Part p;\n    p.sz = sz;\n    p.B = (int)sz.size();\n    p.mx = sz.empty()?0:sz[0];\n    p.mn = sz.empty()?0:sz.back();\n    long long Pin=0, Tin=0, S2=0, S3=0;\n    for(int x: sz){\n        Pin += C2ll(x);\n        Tin += C3ll(x);\n        S2 += 1LL*x*x;\n        S3 += 1LL*x*x*x;\n    }\n    p.Pin = (int)Pin;\n    p.Tin = Tin;\n    p.S2 = S2;\n    p.S3 = S3;\n    return p;\n}\n\nstatic string key_of(const vector<int>& v){\n    string s;\n    s.reserve(v.size()*3);\n    for(int i=0;i<(int)v.size();i++){\n        if(i) s.push_back('-');\n        s += to_string(v[i]);\n    }\n    return s;\n}\n\nstatic double part_dist(const Part& a, const Part& b, int N, int L, long long totalTri){\n    auto norm = [](double x, double s){ return x / (s > 0 ? s : 1.0); };\n    double dE  = norm(abs(a.Pin - b.Pin), (double)L);\n    double dT  = norm((double)llabs(a.Tin - b.Tin), (double)max(1LL, totalTri));\n    double dS2 = norm((double)llabs(a.S2 - b.S2), (double)max(1LL, 1LL*N*N));\n    double dS3 = norm((double)llabs(a.S3 - b.S3), (double)max(1LL, 1LL*N*N*N));\n    double dB  = abs(a.B - b.B) / (double)max(1, N);\n    double dmx = abs(a.mx - b.mx) / (double)max(1, N);\n    double dmn = abs(a.mn - b.mn) / (double)max(1, N);\n    return 2.0*dE + 2.0*dT + 0.8*dS2 + 0.4*dS3 + 0.7*dB + 0.5*dmx + 0.3*dmn;\n}\n\nstatic void enum_partitions(int n, int maxPart, int ms, vector<int>& cur,\n                            unordered_set<string>& seen, vector<Part>& pool, int limit){\n    if ((int)pool.size() >= limit) return;\n    if (n == 0) {\n        string k = key_of(cur);\n        if (seen.insert(k).second) pool.push_back(make_part(cur));\n        return;\n    }\n    int up = min(maxPart, n);\n    for (int x = up; x >= ms; --x) {\n        cur.push_back(x);\n        enum_partitions(n - x, x, ms, cur, seen, pool, limit);\n        cur.pop_back();\n        if ((int)pool.size() >= limit) return;\n    }\n}\n\nstatic void add_part_if_new(int N, int ms, const vector<int>& v,\n                            unordered_set<string>& seen, vector<Part>& pool, int limit){\n    if ((int)pool.size() >= limit) return;\n    vector<int> sz = v;\n    for (int x: sz) if (x < ms) return;\n    if (accumulate(sz.begin(), sz.end(), 0) != N) return;\n    sort(sz.begin(), sz.end(), greater<int>());\n    string k = key_of(sz);\n    if (seen.insert(k).second) pool.push_back(make_part(sz));\n}\n\nstatic void add_deterministic_parts(int N, int ms,\n                                    unordered_set<string>& seen, vector<Part>& pool, int limit){\n    add_part_if_new(N, ms, {N}, seen, pool, limit);\n    for(int a=ms; a<=min(N-ms, ms+28); a++){\n        add_part_if_new(N, ms, {N-a, a}, seen, pool, limit);\n    }\n    for(int B=3; B<=14; B++){\n        if (B*ms > N) break;\n        int rem = N - B*ms;\n        int q = rem / B, r = rem % B;\n        vector<int> v(B, ms+q);\n        for(int i=0;i<r;i++) v[i]++;\n        add_part_if_new(N, ms, v, seen, pool, limit);\n    }\n    // staircase patterns (strictly decreasing base)\n    for(int B=3; B<=12; B++){\n        long long base = 0;\n        for(int i=0;i<B;i++) base += ms + (B-1-i);\n        if (base > N) continue;\n        int rem = (int)(N - base);\n        int q = rem / B, r = rem % B;\n        vector<int> extra(B, q);\n        for(int i=0;i<r;i++) extra[i]++;\n        vector<int> sz(B);\n        for(int i=0;i<B;i++) sz[i] = ms + (B-1-i) + extra[i];\n        add_part_if_new(N, ms, sz, seen, pool, limit);\n        if (rem >= B) {\n            vector<int> ex2 = extra;\n            ex2[0] += B/2;\n            ex2.back() = max(0, ex2.back() - B/2);\n            sort(ex2.begin(), ex2.end(), greater<int>());\n            for(int i=0;i<B;i++) sz[i] = ms + (B-1-i) + ex2[i];\n            add_part_if_new(N, ms, sz, seen, pool, limit);\n        }\n    }\n}\n\nstatic void random_partitions(int N, int ms, double eps, SplitMix64& rng,\n                              unordered_set<string>& seen, vector<Part>& pool, int limit){\n    int Bmax;\n    if (eps <= 0.10) Bmax = 22;\n    else if (eps <= 0.20) Bmax = 15;\n    else if (eps <= 0.30) Bmax = 11;\n    else if (eps <= 0.35) Bmax = 9;\n    else Bmax = 8;\n    Bmax = min(Bmax, N / ms);\n    if (Bmax <= 0) return;\n\n    int tries = 0;\n    int maxTries = limit * 80;\n    while ((int)pool.size() < limit && tries < maxTries) {\n        tries++;\n        int B = rng.next_int(1, Bmax);\n        if (B * ms > N) continue;\n        int rem = N - B * ms;\n\n        vector<int> cuts;\n        cuts.reserve(B+1);\n        cuts.push_back(0);\n        for(int i=0;i<B-1;i++) cuts.push_back(rng.next_int(0, rem));\n        cuts.push_back(rem);\n        sort(cuts.begin(), cuts.end());\n\n        vector<int> sz(B);\n        for(int i=0;i<B;i++) sz[i] = ms + (cuts[i+1] - cuts[i]);\n        sort(sz.begin(), sz.end(), greater<int>());\n        string k = key_of(sz);\n        if (!seen.insert(k).second) continue;\n        pool.push_back(make_part(sz));\n    }\n}\n\nstatic vector<Part> build_pool(int N, int ms, double eps, int poolTarget, SplitMix64& rng){\n    vector<Part> pool;\n    pool.reserve(poolTarget);\n    unordered_set<string> seen;\n    seen.reserve(poolTarget * 2);\n\n    add_deterministic_parts(N, ms, seen, pool, poolTarget);\n    if (N <= 32) {\n        vector<int> cur;\n        enum_partitions(N, N, ms, cur, seen, pool, poolTarget);\n    } else {\n        random_partitions(N, ms, eps, rng, seen, pool, poolTarget);\n    }\n    return pool;\n}\n\n// factorial falling nPk\nstatic long double fall(int n, int k){\n    if (k < 0) return 0;\n    if (k == 0) return 1;\n    if (k > n) return 0;\n    long double r = 1;\n    for(int i=0;i<k;i++) r *= (long double)(n - i);\n    return r;\n}\n\nstatic int initial_internal_edges(const vector<BS>& adj, const vector<int>& order, const vector<int>& part){\n    int N = (int)adj.size();\n    int B = (int)part.size();\n    vector<int> grp(N, -1);\n    vector<BS> gbit(B, BS{0ULL,0ULL});\n    int pos = 0;\n    for(int g=0; g<B; g++){\n        for(int t=0; t<part[g]; t++){\n            int v = order[pos++];\n            grp[v] = g;\n            set_bit(gbit[g], v);\n        }\n    }\n    long long sum = 0;\n    for(int v=0; v<N; v++) sum += pc_and(adj[v], gbit[grp[v]]);\n    return (int)(sum/2);\n}\n\nstatic int local_search_internal_edges(const vector<BS>& adj,\n                                      const vector<int>& initOrder,\n                                      const vector<int>& partSizes,\n                                      SplitMix64& rng,\n                                      int batches,\n                                      int samplesPerBatch)\n{\n    int N = (int)adj.size();\n    int B = (int)partSizes.size();\n\n    vector<int> grp(N, -1);\n    vector<BS> gbit(B, BS{0ULL,0ULL});\n\n    int pos = 0;\n    for (int g=0; g<B; g++){\n        for (int t=0; t<partSizes[g]; t++){\n            int v = initOrder[pos++];\n            grp[v] = g;\n            set_bit(gbit[g], v);\n        }\n    }\n\n    auto internal_edges = [&](){\n        long long sum = 0;\n        for (int v=0; v<N; v++) sum += pc_and(adj[v], gbit[grp[v]]);\n        return (int)(sum/2);\n    };\n\n    int curE = internal_edges();\n    int bestE = curE;\n\n    for (int b=0; b<batches; b++){\n        int bestDelta = 0, bestV = -1, bestU = -1;\n\n        for (int s=0; s<samplesPerBatch; s++){\n            int v = rng.next_int(0, N-1);\n            int u = rng.next_int(0, N-1);\n            if (u == v) continue;\n            int ga = grp[v], gb = grp[u];\n            if (ga == gb) continue;\n\n            int Av = pc_and(adj[v], gbit[ga]);\n            int Bv = pc_and(adj[v], gbit[gb]);\n            int Au = pc_and(adj[u], gbit[ga]);\n            int Bu = pc_and(adj[u], gbit[gb]);\n            int Auv = get_bit(adj[v], u);\n\n            int delta = Au + Bv - Av - Bu - 2*Auv;\n            if (delta > bestDelta) {\n                bestDelta = delta;\n                bestV = v; bestU = u;\n            }\n        }\n\n        if (bestDelta <= 0) break;\n\n        int v = bestV, u = bestU;\n        int ga = grp[v], gb = grp[u];\n\n        flip_bit(gbit[ga], v); flip_bit(gbit[gb], v);\n        flip_bit(gbit[gb], u); flip_bit(gbit[ga], u);\n        grp[v] = gb; grp[u] = ga;\n\n        curE += bestDelta;\n        if (curE > bestE) bestE = curE;\n    }\n    return bestE;\n}\n\nstatic vector<int> topk_idx_desc(const vector<double>& a, int K){\n    int n = (int)a.size();\n    K = min(K, n);\n    vector<int> idx(n);\n    iota(idx.begin(), idx.end(), 0);\n    nth_element(idx.begin(), idx.begin()+K, idx.end(), [&](int i, int j){\n        return a[i] > a[j];\n    });\n    idx.resize(K);\n    sort(idx.begin(), idx.end(), [&](int i, int j){ return a[i] > a[j]; });\n    return idx;\n}\n\n// Build a second robust order: pick high-degree seeds and append their neighbors.\nstatic vector<int> build_neighbor_expand_order(const vector<BS>& adj, const vector<int>& deg){\n    int N = (int)deg.size();\n    vector<int> ord;\n    ord.reserve(N);\n    vector<char> used(N, 0);\n\n    auto pick_next_seed = [&](){\n        int best = -1;\n        for(int i=0;i<N;i++){\n            if(used[i]) continue;\n            if(best < 0 || deg[i] > deg[best]) best = i;\n        }\n        return best;\n    };\n\n    while ((int)ord.size() < N) {\n        int seed = pick_next_seed();\n        if(seed < 0) break;\n        used[seed] = 1;\n        ord.push_back(seed);\n\n        // gather unvisited neighbors\n        vector<int> neigh;\n        neigh.reserve(N);\n        for(int j=0;j<N;j++){\n            if(!used[j] && get_bit(adj[seed], j)) neigh.push_back(j);\n        }\n        sort(neigh.begin(), neigh.end(), [&](int a, int b){ return deg[a] > deg[b]; });\n        for(int v: neigh){\n            if(!used[v]){\n                used[v] = 1;\n                ord.push_back(v);\n            }\n        }\n    }\n\n    // append leftovers (should be none, but safe)\n    for(int i=0;i<N;i++) if(!used[i]) ord.push_back(i);\n    return ord;\n}\n\nint main(){\n    signal(SIGPIPE, SIG_IGN);\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    int ms = choose_ms(eps);\n\n    uint64_t seed0 = 0x123456789abcdefULL;\n    seed0 ^= (uint64_t)M * 1000003ULL;\n    seed0 ^= (uint64_t)llround(eps * 100000.0) * 10007ULL;\n    SplitMix64 rng(seed0);\n\n    int N = chooseN_init(M, eps);\n    const int poolTarget = 30000;\n\n    vector<Part> pool;\n    while(true){\n        pool = build_pool(N, ms, eps, poolTarget, rng);\n        if ((int)pool.size() >= M) break;\n        if (N >= 100) break;\n        N++;\n    }\n\n    int L = N*(N-1)/2;\n    long long totalTriAll = C3ll(N);\n\n    // farthest point sampling\n    int P = (int)pool.size();\n    vector<int> chosen;\n    chosen.reserve(M);\n    vector<char> usedP(P, 0);\n    vector<double> mind(P, 1e100);\n\n    int first = 0;\n    for(int i=1;i<P;i++) if(pool[i].S3 > pool[first].S3) first=i;\n    chosen.push_back(first);\n    usedP[first] = 1;\n    for(int i=0;i<P;i++) mind[i] = part_dist(pool[i], pool[first], N, L, totalTriAll);\n\n    while((int)chosen.size() < M){\n        int best=-1; double bestVal=-1;\n        for(int i=0;i<P;i++){\n            if(usedP[i]) continue;\n            if(mind[i] > bestVal){ bestVal = mind[i]; best = i; }\n        }\n        if(best < 0) break;\n        usedP[best] = 1;\n        chosen.push_back(best);\n        for(int i=0;i<P;i++){\n            if(usedP[i]) continue;\n            double d = part_dist(pool[i], pool[best], N, L, totalTriAll);\n            if(d < mind[i]) mind[i] = d;\n        }\n    }\n    while((int)chosen.size() < M) chosen.push_back(chosen.back());\n\n    // codebook and stats\n    vector<vector<int>> codes(M);\n    vector<int> Pin(M,0);\n    vector<long long> type1(M,0), type2(M,0), type3(M,0);\n    vector<double> muE(M,0.0), muT(M,0.0);\n    unordered_map<string,int> partToIndex;\n    partToIndex.reserve(M*2);\n\n    // wedge moments\n    vector<long double> wedgeMu(M,0.0L), wedgeVar(M,1.0L);\n    static long double Cc[5][5];\n    static bool combInit=false;\n    if(!combInit){\n        for(int i=0;i<=4;i++){\n            for(int j=0;j<=4;j++) Cc[i][j]=0;\n            Cc[i][0]=Cc[i][i]=1;\n            for(int j=1;j<i;j++) Cc[i][j]=Cc[i-1][j-1]+Cc[i-1][j];\n        }\n        combInit=true;\n    }\n\n    for(int k=0;k<M;k++){\n        const Part& pp = pool[chosen[k]];\n        codes[k] = pp.sz;\n        Pin[k] = pp.Pin;\n        partToIndex[key_of(codes[k])] = k;\n\n        long long t1=0, t2=0;\n        for(int s: codes[k]){\n            t1 += C3ll(s);\n            t2 += C2ll(s) * (long long)(N - s);\n        }\n        long long t3 = totalTriAll - t1 - t2;\n        type1[k]=t1; type2[k]=t2; type3[k]=t3;\n\n        muE[k] = eps*(double)L + (1.0 - 2.0*eps)*(double)Pin[k];\n\n        double e = eps;\n        double p1 = (1.0-e)*(1.0-e)*(1.0-e);\n        double p2 = (1.0-e)*e*e;\n        double p3 = e*e*e;\n        muT[k] = (double)type1[k]*p1 + (double)type2[k]*p2 + (double)type3[k]*p3;\n\n        // wedge moments (approx)\n        long double p_in = (long double)(1.0 - eps);\n        long double p_out = (long double)(eps);\n        long double muW=0.0L, varW=0.0L;\n\n        for(int s: codes[k]){\n            int n1 = s-1, n2 = N-s;\n            long double fx[5], fy[5];\n            for(int i=0;i<=4;i++){\n                auto fall = [&](int n, int k)->long double{\n                    if(k<0) return 0;\n                    if(k==0) return 1;\n                    if(k>n) return 0;\n                    long double r=1;\n                    for(int t=0;t<k;t++) r *= (long double)(n-t);\n                    return r;\n                };\n                fx[i] = fall(n1,i) * pow(p_in, (long double)i);\n                fy[i] = fall(n2,i) * pow(p_out, (long double)i);\n            }\n            auto F = [&](int kk)->long double{\n                long double res=0;\n                for(int i=0;i<=kk;i++) res += Cc[kk][i]*fx[i]*fy[kk-i];\n                return res;\n            };\n            long double F2 = F(2), F3 = F(3), F4 = F(4);\n            long double Ew = F2 / 2.0L;\n            long double E_f2_sq = F4 + 4.0L*F3 + 2.0L*F2;\n            long double Var_f2 = max((long double)0.0, E_f2_sq - F2*F2);\n            long double Varw = Var_f2 / 4.0L;\n\n            muW += (long double)s * Ew;\n            varW += (long double)s * Varw;\n        }\n        wedgeMu[k] = muW;\n        wedgeVar[k] = max(varW, 1e-3L);\n    }\n\n    // degree likelihood logP[s][d]\n    vector<vector<double>> logP(N+1, vector<double>(N, -1e100));\n    for (int s=1;s<=N;s++){\n        int n1=s-1, n2=N-s;\n        double p1=1.0-eps, p2=eps;\n        auto pmf1=binom_pmf(n1,p1);\n        auto pmf2=binom_pmf(n2,p2);\n        vector<double> conv(N,0.0);\n        for (int a=0;a<=n1;a++){\n            double pa=pmf1[a]; if(pa==0.0) continue;\n            for (int b=0;b<=n2;b++){\n                double pb=pmf2[b]; if(pb==0.0) continue;\n                conv[a+b] += pa*pb;\n            }\n        }\n        for (int d=0; d<=N-1; d++){\n            logP[s][d] = log(max(conv[d], 1e-300));\n        }\n    }\n\n    // Output graphs\n    cout << N << \"\\n\";\n    for(int k=0;k<M;k++){\n        const auto& part = codes[k];\n        vector<int> blk(N, -1);\n        int cur=0;\n        for(int b=0;b<(int)part.size();b++){\n            for(int t=0;t<part[b];t++) blk[cur++] = b;\n        }\n        while(cur < N) blk[cur++] = (int)part.size();\n\n        string g;\n        g.reserve(L);\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                g.push_back(blk[i]==blk[j] ? '1' : '0');\n            }\n        }\n        cout << g << \"\\n\";\n    }\n    cout.flush();\n\n    // decoder weights (same family as 711M)\n    double varE = max(1e-6, (double)L * eps * (1.0 - eps));\n    double wEdge  = (eps <= 0.05 ? 0.05 : (eps <= 0.20 ? 0.14 : 0.18));\n    double wTri   = (eps <= 0.10 ? 0.12 : (eps <= 0.25 ? 0.22 : 0.28));\n    double wWedge = (eps <= 0.10 ? 0.08 : (eps <= 0.25 ? 0.14 : 0.18));\n\n    bool useInitEdgeScreen = (eps >= 0.12 && eps > 0.0);\n    double alphaInitEdge = (eps >= 0.28 ? 0.22 : (eps >= 0.18 ? 0.16 : 0.12));\n\n    bool useLocal = (eps >= 0.10 && eps > 0.0);\n    double wPart = (eps > 0.0 ? log((1.0 - eps) / eps) : 0.0);\n\n    int topK = min(M, (eps >= 0.30 ? 30 : (eps >= 0.20 ? 22 : 14)));\n    int topKll0 = (useInitEdgeScreen ? min(M, (eps >= 0.30 ? 8 : 6)) : 0);\n    int maxCand = min(M, topK + topKll0);\n\n    int batches = (eps >= 0.30 ? 55 : 45);\n    int samplesPerBatch = 500;\n    int extraRestartsTop = (eps >= 0.28 ? 8 : 0);\n\n    for(int q=0;q<100;q++){\n        string H;\n        if(!(cin >> H)) break;\n\n        vector<int> deg(N, 0);\n        vector<BS> adj(N, BS{0ULL,0ULL});\n        int idx=0, m=0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                char c = H[idx++];\n                if(c=='1'){\n                    deg[i]++; deg[j]++; m++;\n                    set_bit(adj[i], j);\n                    set_bit(adj[j], i);\n                }\n            }\n        }\n\n        if (eps == 0.0) {\n            // exact decode: clique sizes from degrees\n            vector<int> cnt(N,0);\n            for(int d: deg) cnt[d]++;\n            vector<int> part;\n            for(int d=0; d<=N-1; d++){\n                if(cnt[d]==0) continue;\n                int s = d+1;\n                int c = cnt[d];\n                int num = c / s;\n                for(int t=0;t<num;t++) part.push_back(s);\n            }\n            sort(part.begin(), part.end(), greater<int>());\n            auto it = partToIndex.find(key_of(part));\n            int ans = (it==partToIndex.end()? 0 : it->second);\n            cout << ans << \"\\n\";\n            cout.flush();\n            continue;\n        }\n\n        // order1: degree sort\n        vector<int> order1(N);\n        iota(order1.begin(), order1.end(), 0);\n        stable_sort(order1.begin(), order1.end(), [&](int a, int b){ return deg[a] > deg[b]; });\n\n        // order2: neighbor expansion\n        vector<int> order2 = build_neighbor_expand_order(adj, deg);\n\n        // sorted degrees for degree LL\n        vector<int> degSorted = deg;\n        sort(degSorted.begin(), degSorted.end(), greater<int>());\n\n        long long wedgeObs = 0;\n        for(int i=0;i<N;i++) wedgeObs += 1LL*deg[i]*(deg[i]-1)/2;\n\n        long long tri3 = 0;\n        for(int i=0;i<N;i++){\n            for(int j=i+1;j<N;j++){\n                if(get_bit(adj[i], j)) tri3 += pc_and(adj[i], adj[j]);\n            }\n        }\n        long long Tobs = tri3 / 3;\n\n        vector<double> score(M, 0.0);\n        vector<double> ll0(M, -1e300);\n\n        for(int k=0;k<M;k++){\n            const auto& part = codes[k];\n\n            // degree LL (monotone)\n            double sc = 0.0;\n            int pos=0;\n            for(int s: part){\n                for(int t=0;t<s;t++) sc += logP[s][degSorted[pos++]];\n            }\n\n            // edge penalty\n            {\n                double z = (double)m - muE[k];\n                sc += wEdge * (-0.5 * (z*z) / varE);\n            }\n\n            // triangle penalty\n            {\n                double e = eps;\n                double p1 = (1.0-e)*(1.0-e)*(1.0-e);\n                double p2 = (1.0-e)*e*e;\n                double p3 = e*e*e;\n                double varT =\n                    (double)type1[k]*p1*(1.0-p1) +\n                    (double)type2[k]*p2*(1.0-p2) +\n                    (double)type3[k]*p3*(1.0-p3);\n                varT = max(varT, 1e-6);\n                double z = (double)Tobs - muT[k];\n                sc += wTri * (-0.5 * (z*z) / varT);\n            }\n\n            // wedge penalty\n            {\n                long double z = (long double)wedgeObs - wedgeMu[k];\n                sc += wWedge * (double)(-0.5L * (z*z) / wedgeVar[k]);\n            }\n\n            // init-edge screen (use best of two deterministic orders)\n            if (useInitEdgeScreen) {\n                int e1 = initial_internal_edges(adj, order1, part);\n                int e2 = initial_internal_edges(adj, order2, part);\n                int Ein0 = max(e1, e2);\n                double ll_init = wPart * (2.0 * (double)Ein0 - (double)Pin[k]);\n                ll0[k] = ll_init;\n                sc += alphaInitEdge * ll_init;\n            }\n\n            score[k] = sc;\n        }\n\n        // shortlist = union(top score, top ll0)\n        vector<int> cand;\n        vector<char> in(M, 0);\n        auto add_list = [&](const vector<int>& lst){\n            for(int k: lst){\n                if(!in[k]){\n                    in[k]=1;\n                    cand.push_back(k);\n                    if((int)cand.size() >= maxCand) return;\n                }\n            }\n        };\n        add_list(topk_idx_desc(score, topK));\n        if (topKll0 > 0) add_list(topk_idx_desc(ll0, topKll0));\n\n        if (!useLocal) {\n            cout << cand[0] << \"\\n\";\n            cout.flush();\n            continue;\n        }\n\n        sort(cand.begin(), cand.end(), [&](int a, int b){ return score[a] > score[b]; });\n\n        uint64_t qseedBase = seed0 ^ (uint64_t)q * 0x9e3779b97f4a7c15ULL;\n        qseedBase ^= (uint64_t)m * 1000003ULL;\n        qseedBase ^= (uint64_t)(Tobs + 1) * 10007ULL;\n\n        int bestK = cand[0];\n        double bestVal = -1e300;\n\n        for(int r=0;r<(int)cand.size();r++){\n            int k = cand[r];\n            uint64_t base = qseedBase ^ (uint64_t)k * 0x94d049bb133111ebULL;\n\n            // Try local search from both initial orders (robustness)\n            SplitMix64 rr1(base);\n            int bestEin = local_search_internal_edges(adj, order1, codes[k], rr1, batches, samplesPerBatch);\n\n            SplitMix64 rr2(base ^ 0xbf58476d1ce4e5b9ULL);\n            bestEin = max(bestEin, local_search_internal_edges(adj, order2, codes[k], rr2, batches, samplesPerBatch));\n\n            // Extra randomized restart for top few\n            if (r < extraRestartsTop) {\n                vector<int> ord3 = order1;\n                for(int t=0;t<20;t++){\n                    int i = rr1.next_int(0, N-1);\n                    int j = rr1.next_int(0, N-1);\n                    swap(ord3[i], ord3[j]);\n                }\n                SplitMix64 rr3(base ^ 0x94d049bb133111ebULL);\n                bestEin = max(bestEin, local_search_internal_edges(adj, ord3, codes[k], rr3, batches/2, samplesPerBatch));\n            }\n\n            double ll = wPart * (2.0 * (double)bestEin - (double)Pin[k]);\n            double val = ll + 0.02 * score[k]; // stabilizer\n\n            if (val > bestVal){\n                bestVal = val;\n                bestK = k;\n            }\n        }\n\n        cout << bestK << \"\\n\";\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstatic inline long long comb2(long long c) { return c * (c - 1) / 2; }\nstatic inline long double pow4(long double x) { long double s = x * x; return s * s; }\n\nstatic inline uint64_t morton11(uint32_t x, uint32_t y) {\n    uint64_t key = 0;\n    for (int b = 0; b < 11; b++) {\n        key |= (uint64_t)((x >> b) & 1u) << (2 * b);\n        key |= (uint64_t)((y >> b) & 1u) << (2 * b + 1);\n    }\n    return key;\n}\n\nstruct Edge {\n    int u, v;\n    long long w;\n    uint64_t key = 0;\n    int prefDay = 0;\n    long double imp = 0; // [0,1]\n};\n\nstruct Schedule {\n    int D=0, N=0, M=0;\n    vector<int> day;                  // size M\n    vector<vector<int>> inDay;        // D lists\n    vector<int> pos;                  // size M\n    vector<vector<int>> inc;          // D x N removed incident edge counts\n    vector<long double> sumImp;       // D\n\n    void init(int D_, int N_, int M_) {\n        D=D_; N=N_; M=M_;\n        day.assign(M, -1);\n        inDay.assign(D, {});\n        pos.assign(M, -1);\n        inc.assign(D, vector<int>(N, 0));\n        sumImp.assign(D, 0.0L);\n    }\n\n    void assignEdge(int e, int d, const vector<Edge>& edges) {\n        day[e] = d;\n        pos[e] = (int)inDay[d].size();\n        inDay[d].push_back(e);\n        int u = edges[e].u, v = edges[e].v;\n        inc[d][u]++; inc[d][v]++;\n        sumImp[d] += edges[e].imp;\n    }\n\n    void moveEdge(int e, int nd, const vector<Edge>& edges) {\n        int od = day[e];\n        if (od == nd) return;\n        int u = edges[e].u, v = edges[e].v;\n\n        // update inc/sum\n        inc[od][u]--; inc[od][v]--;\n        inc[nd][u]++; inc[nd][v]++;\n        sumImp[od] -= edges[e].imp;\n        sumImp[nd] += edges[e].imp;\n\n        // move in list\n        int p = pos[e];\n        int last = inDay[od].back();\n        inDay[od][p] = last;\n        pos[last] = p;\n        inDay[od].pop_back();\n\n        pos[e] = (int)inDay[nd].size();\n        inDay[nd].push_back(e);\n        day[e] = nd;\n    }\n\n    void swapEdges(int e1, int e2, const vector<Edge>& edges) {\n        int d1 = day[e1], d2 = day[e2];\n        if (d1 == d2) return;\n\n        // update inc/sum\n        auto upd = [&](int d, int v, int dc){ inc[d][v] += dc; };\n        int a1 = edges[e1].u, b1 = edges[e1].v;\n        int a2 = edges[e2].u, b2 = edges[e2].v;\n\n        upd(d1, a1, -1); upd(d1, b1, -1);\n        upd(d2, a1, +1); upd(d2, b1, +1);\n        upd(d2, a2, -1); upd(d2, b2, -1);\n        upd(d1, a2, +1); upd(d1, b2, +1);\n\n        sumImp[d1] = sumImp[d1] - edges[e1].imp + edges[e2].imp;\n        sumImp[d2] = sumImp[d2] - edges[e2].imp + edges[e1].imp;\n\n        // swap in lists using two moves\n        // move e1 to d2\n        {\n            int od = d1, nd = d2;\n            int p = pos[e1];\n            int last = inDay[od].back();\n            inDay[od][p] = last;\n            pos[last] = p;\n            inDay[od].pop_back();\n            pos[e1] = (int)inDay[nd].size();\n            inDay[nd].push_back(e1);\n            day[e1] = nd;\n        }\n        // move e2 to d1\n        {\n            int od = d2, nd = d1;\n            int p = pos[e2];\n            int last = inDay[od].back();\n            inDay[od][p] = last;\n            pos[last] = p;\n            inDay[od].pop_back();\n            pos[e2] = (int)inDay[nd].size();\n            inDay[nd].push_back(e2);\n            day[e2] = nd;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, D, K;\n    cin >> N >> M >> D >> K;\n\n    vector<Edge> edges(M);\n    vector<long long> W(M);\n    vector<vector<pair<int,int>>> g(N);\n    for (int i = 0; i < M; i++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[i].u = u; edges[i].v = v; edges[i].w = w;\n        W[i] = w;\n        g[u].push_back({v, i});\n        g[v].push_back({u, i});\n    }\n    vector<int> X(N), Y(N);\n    for (int i = 0; i < N; i++) cin >> X[i] >> Y[i];\n    vector<int> deg(N);\n    for (int v = 0; v < N; v++) deg[v] = (int)g[v].size();\n\n    auto t_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n    const double TOTAL_LIMIT = 5.80;\n\n    // ---- Build DFS tree + LCA and detect some 2-edge-cut conflicts ----\n    vector<int> parent(N, -1), parentEdge(N, -1), depth(N, 0), tin(N, -1), tout(N, -1), order;\n    vector<char> vis(N, 0), isTreeEdge(M, 0);\n    int timer = 0;\n\n    function<void(int)> dfs = [&](int v) {\n        vis[v] = 1;\n        tin[v] = timer++;\n        order.push_back(v);\n        for (auto [to, eid] : g[v]) {\n            if (to == parent[v]) continue;\n            if (!vis[to]) {\n                parent[to] = v;\n                parentEdge[to] = eid;\n                depth[to] = depth[v] + 1;\n                isTreeEdge[eid] = 1;\n                dfs(to);\n            }\n        }\n        tout[v] = timer++;\n    };\n    dfs(0);\n\n    int LOG = 1;\n    while ((1 << LOG) <= N) LOG++;\n    vector<vector<int>> up(LOG, vector<int>(N, -1));\n    for (int i = 0; i < N; i++) up[0][i] = parent[i];\n    for (int k = 1; k < LOG; k++) for (int i = 0; i < N; i++) {\n        int p = up[k-1][i];\n        up[k][i] = (p == -1 ? -1 : up[k-1][p]);\n    }\n\n    auto is_ancestor = [&](int a, int b) -> bool {\n        return tin[a] <= tin[b] && tout[b] <= tout[a];\n    };\n    auto lca = [&](int a, int b) -> int {\n        if (is_ancestor(a, b)) return a;\n        if (is_ancestor(b, a)) return b;\n        int v = a;\n        for (int k = LOG - 1; k >= 0; k--) {\n            int p = up[k][v];\n            if (p != -1 && !is_ancestor(p, b)) v = p;\n        }\n        return parent[v];\n    };\n\n    vector<long long> cntDelta(N, 0), cntSub(N, 0);\n    vector<int> xorDelta(N, 0), xorSub(N, 0);\n    for (int eid = 0; eid < M; eid++) if (!isTreeEdge[eid]) {\n        int u = edges[eid].u, v = edges[eid].v;\n        int L = lca(u, v);\n        cntDelta[u] += 1;\n        cntDelta[v] += 1;\n        cntDelta[L] -= 2;\n        xorDelta[u] ^= eid;\n        xorDelta[v] ^= eid;\n    }\n    for (int i = 0; i < N; i++) { cntSub[i] = cntDelta[i]; xorSub[i] = xorDelta[i]; }\n    for (int idx = (int)order.size() - 1; idx >= 1; idx--) {\n        int v = order[idx];\n        int p = parent[v];\n        cntSub[p] += cntSub[v];\n        xorSub[p] ^= xorSub[v];\n    }\n\n    vector<vector<int>> conflict(M);\n    vector<pair<int,int>> conflictPairs;\n    for (int v = 1; v < N; v++) {\n        if (cntSub[v] == 1) {\n            int eTree = parentEdge[v];\n            int eNonTree = xorSub[v];\n            if (eTree >= 0 && eNonTree >= 0 && eTree != eNonTree) {\n                conflict[eTree].push_back(eNonTree);\n                conflict[eNonTree].push_back(eTree);\n                int a = min(eTree, eNonTree), b = max(eTree, eNonTree);\n                conflictPairs.push_back({a, b});\n            }\n        }\n    }\n    for (int i = 0; i < M; i++) {\n        auto &c = conflict[i];\n        sort(c.begin(), c.end());\n        c.erase(unique(c.begin(), c.end()), c.end());\n    }\n    sort(conflictPairs.begin(), conflictPairs.end());\n    conflictPairs.erase(unique(conflictPairs.begin(), conflictPairs.end()), conflictPairs.end());\n\n    // ---- sources (farthest sampling) ----\n    int S = min(60, N);\n    vector<int> sources;\n    sources.reserve(S);\n    vector<long long> bestDist2(N, (1LL<<62));\n    sources.push_back(0);\n    bestDist2[0] = 0;\n    for (int it = 1; it < S; it++) {\n        int last = sources.back();\n        for (int v = 0; v < N; v++) {\n            long long dx = X[v] - X[last];\n            long long dy = Y[v] - Y[last];\n            long long d2 = dx*dx + dy*dy;\n            if (d2 < bestDist2[v]) bestDist2[v] = d2;\n        }\n        int farV = 0;\n        for (int v = 1; v < N; v++) if (bestDist2[v] > bestDist2[farV]) farV = v;\n        sources.push_back(farV);\n    }\n\n    // ---- Importance: sampled Brandes edge-betweenness ----\n    long double meanW = 0;\n    for (auto &e : edges) meanW += (long double)e.w;\n    meanW /= max(1, M);\n\n    vector<long double> rawImp(M, 0.0L);\n    const long long INF = (1LL<<62);\n    vector<long long> dist(N);\n    vector<long double> sigma(N), delta(N);\n    vector<vector<pair<int,int>>> preds(N);\n    vector<int> Sorder; Sorder.reserve(N);\n\n    for (int s : sources) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(sigma.begin(), sigma.end(), 0.0L);\n        for (int i = 0; i < N; i++) preds[i].clear();\n        Sorder.clear();\n\n        dist[s] = 0;\n        sigma[s] = 1.0L;\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dist[v]) continue;\n            Sorder.push_back(v);\n            for (auto [to, eid] : g[v]) {\n                long long nd = d + W[eid];\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    pq.push({nd, to});\n                    sigma[to] = sigma[v];\n                    preds[to].clear();\n                    preds[to].push_back({v, eid});\n                } else if (nd == dist[to]) {\n                    sigma[to] += sigma[v];\n                    preds[to].push_back({v, eid});\n                }\n            }\n        }\n        fill(delta.begin(), delta.end(), 0.0L);\n        for (int i = (int)Sorder.size() - 1; i >= 0; i--) {\n            int wv = Sorder[i];\n            long double sw = sigma[wv];\n            if (sw == 0) continue;\n            for (auto [pv, eid] : preds[wv]) {\n                long double c = (sigma[pv] / sw) * (1.0L + delta[wv]);\n                delta[pv] += c;\n                long double factor = 1.0L + (long double)W[eid] / meanW;\n                rawImp[eid] += c * factor;\n            }\n        }\n    }\n    long double maxRaw = 1e-18L;\n    for (int i = 0; i < M; i++) maxRaw = max(maxRaw, rawImp[i]);\n    for (int i = 0; i < M; i++) edges[i].imp = rawImp[i] / maxRaw;\n\n    // ---- Replacement-path boosting for top edges + edgeRisk ----\n    vector<float> edgeRisk(M, 0.0f);\n    {\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b){ return edges[a].imp > edges[b].imp; });\n\n        int T = min(420, M);\n        vector<long long> dist2(N);\n\n        auto altDistUV = [&](int s, int t, int bannedEid, long long limit) -> long long {\n            fill(dist2.begin(), dist2.end(), INF);\n            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            dist2[s] = 0;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [d, v] = pq.top(); pq.pop();\n                if (d != dist2[v]) continue;\n                if (d > limit) return limit + 1;\n                if (v == t) return d;\n                for (auto [to, eid] : g[v]) {\n                    if (eid == bannedEid) continue;\n                    long long nd = d + W[eid];\n                    if (nd < dist2[to]) {\n                        dist2[to] = nd;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            return INF;\n        };\n\n        const long double RISK_CAP = 30.0L;\n        const long double ALPHA = 0.90L;\n        const long double THR = 0.20L;\n        const double BOOST_END = 1.85;\n\n        vector<long double> boosted(M);\n        for (int i = 0; i < M; i++) boosted[i] = edges[i].imp;\n\n        for (int k = 0; k < T; k++) {\n            if (elapsedSec() > BOOST_END) break;\n            int eid = idx[k];\n            int u = edges[eid].u, v = edges[eid].v;\n            long long w = edges[eid].w;\n\n            long long limit = w + (long long)ceill((long double)(w + 1) * RISK_CAP);\n            long long alt = altDistUV(u, v, eid, limit);\n\n            long double riskRatio;\n            if (alt >= INF/4 || alt > limit) riskRatio = RISK_CAP;\n            else {\n                long long det = max(0LL, alt - w);\n                riskRatio = (long double)det / (long double)(w + 1);\n                if (riskRatio > RISK_CAP) riskRatio = RISK_CAP;\n            }\n            if (riskRatio <= THR) continue;\n\n            long double riskN = (riskRatio - THR) / (RISK_CAP - THR);\n            edgeRisk[eid] = (float)riskN;\n            boosted[eid] = edges[eid].imp * (1.0L + ALPHA * riskN);\n        }\n\n        long double mx = 1e-18L;\n        for (int i = 0; i < M; i++) mx = max(mx, boosted[i]);\n        for (int i = 0; i < M; i++) edges[i].imp = boosted[i] / mx;\n    }\n\n    // ---- PrefDay by Morton blocks ----\n    vector<int> idxKey(M);\n    iota(idxKey.begin(), idxKey.end(), 0);\n    for (int i = 0; i < M; i++) {\n        uint32_t mx = (uint32_t)(X[edges[i].u] + X[edges[i].v]);\n        uint32_t my = (uint32_t)(Y[edges[i].u] + Y[edges[i].v]);\n        edges[i].key = morton11(mx, my);\n    }\n    sort(idxKey.begin(), idxKey.end(), [&](int a, int b){ return edges[a].key < edges[b].key; });\n\n    vector<int> desiredSize(D, M / D);\n    for (int d = 0; d < (M % D); d++) desiredSize[d]++;\n\n    {\n        int cur = 0;\n        for (int d = 0; d < D; d++) {\n            for (int t = 0; t < desiredSize[d]; t++) {\n                int e = idxKey[cur++];\n                edges[e].prefDay = d;\n            }\n        }\n    }\n\n    // ---- Dijkstra for evaluation ----\n    auto dijkstraSkipDay = [&](int s, int skipDay, const vector<int>& dayOfEdge, vector<long long>& dout) {\n        fill(dout.begin(), dout.end(), INF);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n        dout[s] = 0;\n        pq.push({0, s});\n        while (!pq.empty()) {\n            auto [d, v] = pq.top(); pq.pop();\n            if (d != dout[v]) continue;\n            for (auto [to, eid] : g[v]) {\n                if (skipDay >= 0 && dayOfEdge[eid] == skipDay) continue;\n                long long nd = d + W[eid];\n                if (nd < dout[to]) {\n                    dout[to] = nd;\n                    pq.push({nd, to});\n                }\n            }\n        }\n    };\n\n    // eval sources and base distances\n    int EvalMax = min(10, (int)sources.size());\n    vector<int> evalSources(sources.begin(), sources.begin() + EvalMax);\n    vector<vector<long long>> distBase(EvalMax, vector<long long>(N, INF));\n    vector<long long> tmpDist(N, INF);\n    for (int i = 0; i < EvalMax; i++) {\n        // skipDay=-1 => no closures; pass dummy dayOfEdge (all -1)\n        static vector<int> dummy;\n        dummy.assign(M, -1);\n        dijkstraSkipDay(evalSources[i], -1, dummy, distBase[i]);\n    }\n\n    auto dayDamage = [&](const Schedule& sc, int day, int evalCnt) -> long long {\n        long long score = 0;\n        for (int si = 0; si < evalCnt; si++) {\n            dijkstraSkipDay(evalSources[si], day, sc.day, tmpDist);\n            for (int v = 0; v < N; v++) {\n                long long a = tmpDist[v];\n                if (a >= INF/4) a = 1000000000LL;\n                long long b = distBase[si][v];\n                long long incd = a - b;\n                if (incd > 0) score += incd;\n            }\n        }\n        return score;\n    };\n\n    auto totalDamage = [&](const Schedule& sc, int evalCnt) -> long long {\n        long long tot = 0;\n        for (int d = 0; d < D; d++) tot += dayDamage(sc, d, evalCnt);\n        return tot;\n    };\n\n    // ---- feasibility checks ----\n    auto canPlaceEdge = [&](const Schedule& sc, int e, int d) -> bool {\n        if ((int)sc.inDay[d].size() >= K) return false;\n        for (int p : conflict[e]) if (sc.day[p] == d) return false;\n        int u = edges[e].u, v = edges[e].v;\n        if (sc.inc[d][u] + 1 > deg[u] - 1) return false;\n        if (sc.inc[d][v] + 1 > deg[v] - 1) return false;\n        return true;\n    };\n\n    // ---- fix conflicts ----\n    auto fixConflicts = [&](Schedule& sc) {\n        for (auto [a,b] : conflictPairs) {\n            if (sc.day[a] != sc.day[b]) continue;\n            int bad = sc.day[a];\n            int moveE = (edges[a].imp < edges[b].imp ? a : b);\n\n            bool moved = false;\n            // try days with slack (small size first)\n            vector<int> days(D);\n            iota(days.begin(), days.end(), 0);\n            sort(days.begin(), days.end(), [&](int x, int y){ return sc.inDay[x].size() < sc.inDay[y].size(); });\n            for (int nd : days) {\n                if (nd == bad) continue;\n                if (!canPlaceEdge(sc, moveE, nd)) continue;\n                sc.moveEdge(moveE, nd, edges);\n                moved = true;\n                break;\n            }\n            (void)moved;\n        }\n    };\n\n    // ---- fix isolation ----\n    auto fixIsolation = [&](Schedule& sc) {\n        for (int rep = 0; rep < 5000; rep++) {\n            bool changed = false;\n            for (int d = 0; d < D && !changed; d++) {\n                for (int v = 0; v < N && !changed; v++) {\n                    if (sc.inc[d][v] == deg[v]) {\n                        int bestE = -1;\n                        long double bestImp = 1e100L;\n                        for (auto [to, eid] : g[v]) {\n                            (void)to;\n                            if (sc.day[eid] != d) continue;\n                            if (edges[eid].imp < bestImp) bestImp = edges[eid].imp, bestE = eid;\n                        }\n                        if (bestE == -1) continue;\n                        for (int nd = 0; nd < D; nd++) {\n                            if (nd == d) continue;\n                            if (canPlaceEdge(sc, bestE, nd)) {\n                                sc.moveEdge(bestE, nd, edges);\n                                changed = true;\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    };\n\n    // ---- connectivity repair ----\n    vector<int> comp(N, -1);\n    auto connectivityRepair = [&](Schedule& sc, int budget, double endTime) {\n        deque<int> q;\n        while (budget-- > 0 && elapsedSec() < endTime) {\n            bool any = false;\n            for (int d = 0; d < D; d++) {\n                fill(comp.begin(), comp.end(), -1);\n                int cid = 0;\n                for (int s = 0; s < N; s++) if (comp[s] == -1) {\n                    comp[s] = cid++;\n                    q.clear(); q.push_back(s);\n                    while (!q.empty()) {\n                        int v = q.front(); q.pop_front();\n                        for (auto [to, eid] : g[v]) {\n                            if (sc.day[eid] == d) continue; // closed\n                            if (comp[to] != -1) continue;\n                            comp[to] = comp[v];\n                            q.push_back(to);\n                        }\n                    }\n                }\n                if (cid <= 1) continue;\n\n                any = true;\n                vector<int> cand;\n                cand.reserve(sc.inDay[d].size());\n                for (int e : sc.inDay[d]) if (comp[edges[e].u] != comp[edges[e].v]) cand.push_back(e);\n                if (cand.empty()) cand = sc.inDay[d];\n\n                sort(cand.begin(), cand.end(), [&](int a, int b){ return edges[a].imp < edges[b].imp; });\n\n                bool moved = false;\n                vector<int> days(D);\n                iota(days.begin(), days.end(), 0);\n                sort(days.begin(), days.end(), [&](int x, int y){ return sc.inDay[x].size() < sc.inDay[y].size(); });\n\n                for (int e : cand) {\n                    int od = sc.day[e];\n                    for (int nd : days) {\n                        if (nd == od) continue;\n                        if (canPlaceEdge(sc, e, nd)) {\n                            sc.moveEdge(e, nd, edges);\n                            moved = true;\n                            break;\n                        }\n                    }\n                    if (moved) break;\n                }\n                break; // re-evaluate after one move\n            }\n            if (!any) break;\n        }\n    };\n\n    // ---- greedy init (deterministic / randomized tie-break) ----\n    auto greedyInit = [&](Schedule& sc, XorShift64& rng, bool randomized) {\n        sc.init(D, N, M);\n\n        vector<int> idxImp(M);\n        iota(idxImp.begin(), idxImp.end(), 0);\n        sort(idxImp.begin(), idxImp.end(), [&](int a, int b){\n            return edges[a].imp > edges[b].imp;\n        });\n\n        auto scoreDay = [&](int e, int d) -> long double {\n            long double imp = edges[e].imp;\n            long double dImp = pow4(sc.sumImp[d] + imp) - pow4(sc.sumImp[d]);\n            long double sz0 = (long double)sc.inDay[d].size() - (long double)desiredSize[d];\n            long double sz1 = (long double)(sc.inDay[d].size() + 1) - (long double)desiredSize[d];\n            long double dSz = (sz1*sz1 - sz0*sz0);\n            long double dPd = (long double)abs(d - edges[e].prefDay);\n            return 1.0L * dImp + 0.18L * dSz + 0.02L * dPd;\n        };\n\n        for (int e : idxImp) {\n            int pd = edges[e].prefDay;\n            vector<pair<long double,int>> cand;\n            int R = randomized ? 3 : 2;\n            for (int r = 0; r <= R; r++) {\n                int d1 = pd - r;\n                int d2 = pd + r;\n                if (d1 >= 0 && canPlaceEdge(sc, e, d1)) cand.push_back({scoreDay(e, d1), d1});\n                if (d2 < D && d2 != d1 && canPlaceEdge(sc, e, d2)) cand.push_back({scoreDay(e, d2), d2});\n            }\n            if (cand.empty()) {\n                // relax isolation constraint if necessary (very rare), then fix later\n                for (int d = 0; d < D; d++) {\n                    if ((int)sc.inDay[d].size() >= K) continue;\n                    bool ok = true;\n                    for (int p : conflict[e]) if (sc.day[p] == d) { ok = false; break; }\n                    if (!ok) continue;\n                    cand.push_back({scoreDay(e, d) + 10.0L, d});\n                }\n            }\n\n            sort(cand.begin(), cand.end());\n            int chosen = cand[0].second;\n            if (randomized && (int)cand.size() >= 2) {\n                int top = min(3, (int)cand.size());\n                long double best = cand[0].first;\n                vector<long double> w(top);\n                long double sumw = 0;\n                for (int i = 0; i < top; i++) {\n                    long double diff = cand[i].first - best;\n                    long double wi = expl(-(double)diff / 0.05);\n                    w[i] = wi;\n                    sumw += wi;\n                }\n                long double r = rng.nextDouble() * (double)sumw;\n                int pick = 0;\n                for (; pick < top; pick++) {\n                    r -= w[pick];\n                    if (r <= 0) break;\n                }\n                if (pick >= top) pick = top-1;\n                chosen = cand[pick].second;\n            }\n            sc.assignEdge(e, chosen, edges);\n        }\n\n        fixConflicts(sc);\n        fixIsolation(sc);\n    };\n\n    // ---- SA (same objective as best versions) ----\n    auto runSA = [&](Schedule& sc, XorShift64& rng, double endTime) {\n        const long double Aobj=1.0L, PV=4.0L, SZ=0.25L, Bobj=0.005L;\n\n        long double sumImp4 = 0;\n        long double sizeCost = 0;\n        long long totalPairs = 0;\n        long long misCount = 0;\n\n        for (int d = 0; d < D; d++) {\n            sumImp4 += pow4(sc.sumImp[d]);\n            long double diff = (long double)sc.inDay[d].size() - (long double)desiredSize[d];\n            sizeCost += diff * diff;\n            for (int v = 0; v < N; v++) totalPairs += comb2(sc.inc[d][v]);\n        }\n        for (int e = 0; e < M; e++) if (sc.day[e] != edges[e].prefDay) misCount++;\n\n        long double curCost = Aobj*sumImp4 + PV*(long double)totalPairs + SZ*sizeCost + Bobj*(long double)misCount;\n\n        auto deltaPairsMove = [&](int e, int od, int nd)->long long{\n            int u = edges[e].u, v = edges[e].v;\n            long long dp = 0;\n            auto one = [&](int day, int vert, int dc){\n                int oldc = sc.inc[day][vert];\n                int newc = oldc + dc;\n                dp += (comb2(newc) - comb2(oldc));\n            };\n            one(od,u,-1); one(od,v,-1);\n            one(nd,u,+1); one(nd,v,+1);\n            return dp;\n        };\n\n        auto deltaPairsSwap = [&](int e1,int e2,int d1,int d2)->long long{\n            vector<int> vs = {edges[e1].u,edges[e1].v,edges[e2].u,edges[e2].v};\n            sort(vs.begin(),vs.end());\n            vs.erase(unique(vs.begin(),vs.end()),vs.end());\n            long long dp=0;\n            for(int v:vs){\n                int c1=sc.inc[d1][v], c2=sc.inc[d2][v];\n                int nc1=c1, nc2=c2;\n                auto decinc=[&](int e, int from, int to){\n                    if(edges[e].u==v){ if(from==d1) nc1--; else nc2--; if(to==d1) nc1++; else nc2++; }\n                    if(edges[e].v==v){ if(from==d1) nc1--; else nc2--; if(to==d1) nc1++; else nc2++; }\n                };\n                // e1: d1->d2, e2: d2->d1\n                if(edges[e1].u==v){ nc1--; nc2++; }\n                if(edges[e1].v==v){ nc1--; nc2++; }\n                if(edges[e2].u==v){ nc2--; nc1++; }\n                if(edges[e2].v==v){ nc2--; nc1++; }\n                dp += (comb2(nc1)-comb2(c1)) + (comb2(nc2)-comb2(c2));\n            }\n            return dp;\n        };\n\n        auto hardMove = [&](int e, int nd)->bool{\n            int od=sc.day[e];\n            if(od==nd) return false;\n            if((int)sc.inDay[nd].size()>=K) return false;\n            for(int p: conflict[e]) if(sc.day[p]==nd) return false;\n            int u=edges[e].u, v=edges[e].v;\n            if(sc.inc[nd][u]+1>deg[u]-1) return false;\n            if(sc.inc[nd][v]+1>deg[v]-1) return false;\n            return true;\n        };\n\n        auto hardSwap = [&](int e1,int e2)->bool{\n            int d1=sc.day[e1], d2=sc.day[e2];\n            if(d1==d2) return false;\n            auto newDay=[&](int e)->int{\n                if(e==e1) return d2;\n                if(e==e2) return d1;\n                return sc.day[e];\n            };\n            for(int p: conflict[e1]) if(newDay(p)==d2) return false;\n            for(int p: conflict[e2]) if(newDay(p)==d1) return false;\n\n            vector<int> vs = {edges[e1].u,edges[e1].v,edges[e2].u,edges[e2].v};\n            sort(vs.begin(),vs.end());\n            vs.erase(unique(vs.begin(),vs.end()),vs.end());\n            for(int v:vs){\n                int c1=sc.inc[d1][v], c2=sc.inc[d2][v];\n                if(edges[e1].u==v){ c1--; c2++; }\n                if(edges[e1].v==v){ c1--; c2++; }\n                if(edges[e2].u==v){ c2--; c1++; }\n                if(edges[e2].v==v){ c2--; c1++; }\n                if(c1>deg[v]-1) return false;\n                if(c2>deg[v]-1) return false;\n            }\n            return true;\n        };\n\n        while (elapsedSec() < endTime) {\n            double t = elapsedSec() / max(1e-9, endTime);\n            double T = 3.5 * (1.0 - t) + 0.05 * t;\n\n            int op = rng.nextInt(100);\n            if (op < 72) {\n                int e1 = rng.nextInt(M);\n                int e2 = rng.nextInt(M);\n                if (e1 == e2) continue;\n                if (sc.day[e1] == sc.day[e2]) continue;\n                if (!hardSwap(e1, e2)) continue;\n                int d1 = sc.day[e1], d2 = sc.day[e2];\n\n                long double s1 = sc.sumImp[d1], s2 = sc.sumImp[d2];\n                long double i1 = edges[e1].imp, i2 = edges[e2].imp;\n                long double ns1 = s1 - i1 + i2;\n                long double ns2 = s2 - i2 + i1;\n                long double dImp4 = pow4(ns1) + pow4(ns2) - pow4(s1) - pow4(s2);\n\n                long long oldMis = (d1 != edges[e1].prefDay) + (d2 != edges[e2].prefDay);\n                long long newMis = (d2 != edges[e1].prefDay) + (d1 != edges[e2].prefDay);\n                long long dMis = newMis - oldMis;\n\n                long long dPairs = deltaPairsSwap(e1,e2,d1,d2);\n\n                long double deltaC = Aobj*dImp4 + PV*(long double)dPairs + Bobj*(long double)dMis;\n                if (deltaC <= 0 || rng.nextDouble() < exp(-(double)deltaC / T)) {\n                    sc.swapEdges(e1, e2, edges);\n                    sumImp4 += dImp4;\n                    totalPairs += dPairs;\n                    misCount += dMis;\n                    curCost += deltaC;\n                }\n            } else {\n                int e = rng.nextInt(M);\n                int nd = rng.nextInt(D);\n                if (!hardMove(e, nd)) continue;\n                int od = sc.day[e];\n\n                long double so = sc.sumImp[od], sn = sc.sumImp[nd];\n                long double imp = edges[e].imp;\n                long double nso = so - imp, nsn = sn + imp;\n                long double dImp4 = pow4(nso) + pow4(nsn) - pow4(so) - pow4(sn);\n\n                long double sizO = (long double)sc.inDay[od].size();\n                long double sizN = (long double)sc.inDay[nd].size();\n                long double dso = sizO - (long double)desiredSize[od];\n                long double dsn = sizN - (long double)desiredSize[nd];\n                long double dso1 = (sizO - 1.0L) - (long double)desiredSize[od];\n                long double dsn1 = (sizN + 1.0L) - (long double)desiredSize[nd];\n                long double dSize = (dso1*dso1 + dsn1*dsn1) - (dso*dso + dsn*dsn);\n\n                long long oldMis = (od != edges[e].prefDay);\n                long long newMis = (nd != edges[e].prefDay);\n                long long dMis = newMis - oldMis;\n\n                long long dPairs = deltaPairsMove(e, od, nd);\n\n                long double deltaC = Aobj*dImp4 + PV*(long double)dPairs + SZ*dSize + Bobj*(long double)dMis;\n                if (deltaC <= 0 || rng.nextDouble() < exp(-(double)deltaC / T)) {\n                    sc.moveEdge(e, nd, edges);\n                    sumImp4 += dImp4;\n                    sizeCost += dSize;\n                    totalPairs += dPairs;\n                    misCount += dMis;\n                    curCost += deltaC;\n                }\n            }\n        }\n    };\n\n    // ---- eval-guided improvement ----\n    auto evalImprove = [&](Schedule& sc, XorShift64& rng, double endTime, int evalCnt) {\n        vector<long long> dmg(D, 0);\n        for (int d = 0; d < D; d++) dmg[d] = dayDamage(sc, d, evalCnt);\n\n        auto canMove = [&](int e, int nd)->bool { return canPlaceEdge(sc, e, nd); };\n        auto canSwap = [&](int e1,int e2)->bool {\n            int d1=sc.day[e1], d2=sc.day[e2];\n            if(d1==d2) return false;\n            auto newDay=[&](int e)->int{\n                if(e==e1) return d2;\n                if(e==e2) return d1;\n                return sc.day[e];\n            };\n            for(int p: conflict[e1]) if(newDay(p)==d2) return false;\n            for(int p: conflict[e2]) if(newDay(p)==d1) return false;\n\n            vector<int> vs={edges[e1].u,edges[e1].v,edges[e2].u,edges[e2].v};\n            sort(vs.begin(),vs.end());\n            vs.erase(unique(vs.begin(),vs.end()),vs.end());\n            for(int v:vs){\n                int c1=sc.inc[d1][v], c2=sc.inc[d2][v];\n                if(edges[e1].u==v){ c1--; c2++; }\n                if(edges[e1].v==v){ c1--; c2++; }\n                if(edges[e2].u==v){ c2--; c1++; }\n                if(edges[e2].v==v){ c2--; c1++; }\n                if(c1>deg[v]-1) return false;\n                if(c2>deg[v]-1) return false;\n            }\n            return true;\n        };\n\n        auto badScore = [&](int e)->long double {\n            return edges[e].imp * (1.0L + 0.25L * (long double)edgeRisk[e]);\n        };\n\n        while (elapsedSec() < endTime) {\n            // top-2 worst days\n            vector<int> days(D);\n            iota(days.begin(), days.end(), 0);\n            sort(days.begin(), days.end(), [&](int a, int b){ return dmg[a] > dmg[b]; });\n            int hiCandidates = min(2, D);\n\n            bool anyImproved = false;\n\n            for (int hiIdx = 0; hiIdx < hiCandidates && !anyImproved; hiIdx++) {\n                int hi = days[hiIdx];\n\n                vector<int> lows(D);\n                iota(lows.begin(), lows.end(), 0);\n                sort(lows.begin(), lows.end(), [&](int a, int b){ return dmg[a] < dmg[b]; });\n\n                bool improved = false;\n                int loTry = min(4, D);\n\n                for (int tlo = 0; tlo < loTry && !improved; tlo++) {\n                    int lo = lows[tlo];\n                    if (lo == hi) continue;\n\n                    // MOVE (if slack)\n                    if ((int)sc.inDay[lo].size() < K) {\n                        int sz = (int)sc.inDay[hi].size();\n                        if (sz > 0) {\n                            int bestE = -1;\n                            long double bestK = -1;\n                            int sampleCnt = min(80, sz);\n                            for (int t = 0; t < sampleCnt; t++) {\n                                int e = sc.inDay[hi][rng.nextInt(sz)];\n                                if (!canMove(e, lo)) continue;\n                                long double k = badScore(e);\n                                if (k > bestK) bestK = k, bestE = e;\n                            }\n                            if (bestE != -1) {\n                                long long oldHi = dmg[hi], oldLo = dmg[lo];\n                                sc.moveEdge(bestE, lo, edges);\n                                long long newHi = dayDamage(sc, hi, evalCnt);\n                                long long newLo = dayDamage(sc, lo, evalCnt);\n                                if (newHi + newLo < oldHi + oldLo) {\n                                    dmg[hi] = newHi; dmg[lo] = newLo;\n                                    improved = true;\n                                    break;\n                                } else {\n                                    sc.moveEdge(bestE, hi, edges); // revert\n                                }\n                            }\n                        }\n                    }\n\n                    // SWAP: sharp candidate sets\n                    {\n                        int szH = (int)sc.inDay[hi].size();\n                        int szL = (int)sc.inDay[lo].size();\n                        if (szH == 0 || szL == 0) continue;\n\n                        vector<int> candH, candL;\n                        candH.reserve(8);\n                        candL.reserve(8);\n\n                        int sampH = min(80, szH);\n                        int sampL = min(80, szL);\n                        for (int t = 0; t < sampH; t++) candH.push_back(sc.inDay[hi][rng.nextInt(szH)]);\n                        for (int t = 0; t < sampL; t++) candL.push_back(sc.inDay[lo][rng.nextInt(szL)]);\n\n                        sort(candH.begin(), candH.end(), [&](int a, int b){ return badScore(a) > badScore(b); });\n                        candH.erase(unique(candH.begin(), candH.end()), candH.end());\n                        if ((int)candH.size() > 8) candH.resize(8);\n\n                        sort(candL.begin(), candL.end(), [&](int a, int b){ return edges[a].imp < edges[b].imp; });\n                        candL.erase(unique(candL.begin(), candL.end()), candL.end());\n                        if ((int)candL.size() > 8) candL.resize(8);\n\n                        int bestE1 = -1, bestE2 = -1;\n                        long double bestK = -1;\n                        for (int e1 : candH) for (int e2 : candL) {\n                            if (edges[e1].imp < edges[e2].imp) continue;\n                            if (!canSwap(e1, e2)) continue;\n                            long double k = badScore(e1) - edges[e2].imp;\n                            if (k > bestK) bestK = k, bestE1 = e1, bestE2 = e2;\n                        }\n\n                        if (bestE1 != -1) {\n                            long long oldHi = dmg[hi], oldLo = dmg[lo];\n                            sc.swapEdges(bestE1, bestE2, edges);\n                            long long newHi = dayDamage(sc, hi, evalCnt);\n                            long long newLo = dayDamage(sc, lo, evalCnt);\n                            if (newHi + newLo < oldHi + oldLo) {\n                                dmg[hi] = newHi; dmg[lo] = newLo;\n                                improved = true;\n                                break;\n                            } else {\n                                sc.swapEdges(bestE1, bestE2, edges); // revert\n                            }\n                        }\n                    }\n                }\n\n                if (improved) anyImproved = true;\n            }\n\n            if (!anyImproved) break;\n        }\n    };\n\n    // ---- Multi-start: 2 candidates, select by proxy ----\n    int attempts = 2;\n    double t0 = elapsedSec();\n    double rem = TOTAL_LIMIT - t0;\n    if (rem < 1.0) attempts = 1;\n\n    double finalPhase = min(1.8, max(1.0, rem * 0.35));\n    double attemptPhase = (rem - finalPhase) / attempts;\n\n    vector<Schedule> candSched(attempts);\n    vector<long long> candProxy(attempts, (1LL<<62));\n\n    for (int a = 0; a < attempts; a++) {\n        if (elapsedSec() > TOTAL_LIMIT - 0.4) break;\n        double startA = elapsedSec();\n        double endA = startA + attemptPhase;\n\n        XorShift64 rng(123456789 + 99991ull * (uint64_t)a);\n        greedyInit(candSched[a], rng, (a == 1));\n\n        // short SA\n        double endSA = startA + attemptPhase * 0.70;\n        runSA(candSched[a], rng, min(endSA, TOTAL_LIMIT));\n\n        // light connectivity repair before proxy\n        connectivityRepair(candSched[a], 200, min(endA, TOTAL_LIMIT));\n\n        // proxy evaluation with fewer sources\n        int proxyEval = min(6, EvalMax);\n        candProxy[a] = totalDamage(candSched[a], proxyEval);\n    }\n\n    int bestIdx = 0;\n    for (int a = 1; a < attempts; a++) if (candProxy[a] < candProxy[bestIdx]) bestIdx = a;\n\n    Schedule best = candSched[bestIdx];\n\n    // ---- Final stage on best schedule ----\n    double endFinal = TOTAL_LIMIT - 0.06;\n\n    // full connectivity repair before eval\n    connectivityRepair(best, 1500, endFinal);\n\n    // eval-guided improvement with more sources\n    evalImprove(best, *(new XorShift64(7777777)), min(endFinal, TOTAL_LIMIT), EvalMax);\n\n    // final connectivity repair (small)\n    connectivityRepair(best, 800, endFinal);\n\n    // final isolation fix (safety)\n    fixIsolation(best);\n\n    // Output\n    for (int i = 0; i < M; i++) {\n        if (i) cout << ' ';\n        cout << (best.day[i] + 1);\n    }\n    cout << \"\\n\";\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const { return chrono::duration<double>(chrono::steady_clock::now() - st).count(); }\n};\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed=88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int next_int(int mod) { return (int)(next_u64() % (uint64_t)mod); }\n};\n\nstruct Segment {\n    int x, y, z;\n    int axis; // 0:x 1:y 2:z\n    int len;\n};\n\nstatic inline int idx3(int D, int x, int y, int z) { return x * D * D + y * D + z; }\n\nstatic long long volume_of(const vector<uint8_t>& occ) {\n    long long v = 0;\n    for (auto c : occ) v += (c != 0);\n    return v;\n}\n\nstatic uint64_t fnv1a64(const string& s, uint64_t h=1469598103934665603ull) {\n    for (unsigned char c : s) { h ^= (uint64_t)c; h *= 1099511628211ull; }\n    return h;\n}\nstatic uint64_t hash_occ(const vector<uint8_t>& occ) {\n    uint64_t h = 1469598103934665603ull;\n    for (uint8_t b : occ) {\n        h ^= (uint64_t)(b + 1);\n        h *= 1099511628211ull;\n        h ^= (h >> 32);\n    }\n    return h;\n}\n\n// ---- silhouette info ----\nstruct SilInfo {\n    vector<uint8_t> allow; // D^3\n    vector<vector<int>> X, Y; // per z\n    int maxVol;\n};\n\nstatic SilInfo build_allow(int D, const vector<string>& f, const vector<string>& r) {\n    SilInfo si;\n    si.allow.assign(D*D*D, 0);\n    si.X.assign(D, {});\n    si.Y.assign(D, {});\n    for (int z=0; z<D; z++) {\n        for (int x=0; x<D; x++) if (f[z][x]=='1') si.X[z].push_back(x);\n        for (int y=0; y<D; y++) if (r[z][y]=='1') si.Y[z].push_back(y);\n        for (int x: si.X[z]) for (int y: si.Y[z]) si.allow[idx3(D,x,y,z)] = 1;\n    }\n    si.maxVol = (int)volume_of(si.allow);\n    return si;\n}\n\nstatic vector<int> choose_stable_sequence(const vector<vector<int>>& opts) {\n    int D = (int)opts.size();\n    vector<vector<int>> par(D);\n    vector<long long> dp_prev, dp_cur;\n    dp_prev.assign(opts[0].size(), 0);\n    par[0].assign(opts[0].size(), -1);\n\n    for (int z=1; z<D; z++) {\n        dp_cur.assign(opts[z].size(), LLONG_MIN/4);\n        par[z].assign(opts[z].size(), -1);\n        for (int j=0; j<(int)opts[z-1].size(); j++) {\n            for (int k=0; k<(int)opts[z].size(); k++) {\n                long long cand = dp_prev[j] + (opts[z][k] == opts[z-1][j] ? 1 : 0);\n                if (cand > dp_cur[k]) { dp_cur[k]=cand; par[z][k]=j; }\n            }\n        }\n        dp_prev.swap(dp_cur);\n    }\n    int best=0;\n    for (int k=1; k<(int)dp_prev.size(); k++) if (dp_prev[k] > dp_prev[best]) best=k;\n\n    vector<int> seq(D);\n    int cur=best;\n    for (int z=D-1; z>=0; z--) {\n        seq[z]=opts[z][cur];\n        cur=par[z][cur];\n        if (z==0) break;\n    }\n    return seq;\n}\n\nstatic int choose_global_hub(const vector<vector<int>>& opts, int D) {\n    vector<int> freq(D,0);\n    for (auto &v: opts) for (int a: v) freq[a]++;\n    int best=0;\n    for (int i=1;i<D;i++) if (freq[i] > freq[best]) best=i;\n    return best;\n}\n\n// ---- constructions ----\nstatic vector<uint8_t> build_dense(int, const SilInfo& si) { return si.allow; }\n\nstatic vector<uint8_t> build_min_edgecover(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D,0);\n    for (int z=0; z<D; z++) {\n        const auto& xs=si.X[z];\n        const auto& ys=si.Y[z];\n        int nx=(int)xs.size(), ny=(int)ys.size();\n        if (nx>=ny) {\n            for (int j=0;j<ny;j++) occ[idx3(D,xs[j],ys[j],z)]=1;\n            for (int j=ny;j<nx;j++) occ[idx3(D,xs[j],ys[0],z)]=1;\n        } else {\n            for (int j=0;j<nx;j++) occ[idx3(D,xs[j],ys[j],z)]=1;\n            for (int j=nx;j<ny;j++) occ[idx3(D,xs[0],ys[j],z)]=1;\n        }\n    }\n    return occ;\n}\n\nstatic vector<uint8_t> build_star_stable(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D,0);\n    vector<int> x0=choose_stable_sequence(si.X);\n    vector<int> y0=choose_stable_sequence(si.Y);\n    for (int z=0; z<D; z++) {\n        for (int x: si.X[z]) occ[idx3(D,x,y0[z],z)]=1;\n        for (int y: si.Y[z]) occ[idx3(D,x0[z],y,z)]=1;\n    }\n    return occ;\n}\n\nstatic vector<uint8_t> build_star_globalhub(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D,0);\n    int gx=choose_global_hub(si.X,D);\n    int gy=choose_global_hub(si.Y,D);\n    for (int z=0; z<D; z++) {\n        int xhub=gx, yhub=gy;\n        if (find(si.X[z].begin(), si.X[z].end(), xhub)==si.X[z].end()) xhub=si.X[z][0];\n        if (find(si.Y[z].begin(), si.Y[z].end(), yhub)==si.Y[z].end()) yhub=si.Y[z][0];\n        for (int x: si.X[z]) occ[idx3(D,x,yhub,z)]=1;\n        for (int y: si.Y[z]) occ[idx3(D,xhub,y,z)]=1;\n    }\n    return occ;\n}\n\nstatic vector<uint8_t> build_continuity_edgecover(int D, const SilInfo& si) {\n    vector<uint8_t> occ(D*D*D,0);\n    vector<vector<int>> W(D, vector<int>(D,0));\n    for (int z=0; z<D; z++) for (int x: si.X[z]) for (int y: si.Y[z]) W[x][y]++;\n\n    vector<vector<uint8_t>> prev(D, vector<uint8_t>(D,0));\n    const int BONUS=1000;\n\n    for (int z=0; z<D; z++) {\n        const auto& xs=si.X[z];\n        const auto& ys=si.Y[z];\n        int nx=(int)xs.size(), ny=(int)ys.size();\n        vector<uint8_t> covX(D,0), covY(D,0);\n        vector<pair<int,int>> edges;\n\n        auto score = [&](int x,int y)->int { return W[x][y] + (prev[x][y]?BONUS:0); };\n\n        if (nx>=ny) {\n            for (int x: xs) {\n                int besty=ys[0], bests=-1;\n                for (int y: ys) { int s=score(x,y); if (s>bests){bests=s; besty=y;} }\n                edges.push_back({x,besty});\n                covX[x]=1; covY[besty]=1;\n            }\n            for (int y: ys) if (!covY[y]) {\n                int bestx=xs[0], bests=-1;\n                for (int x: xs) { int s=score(x,y); if (s>bests){bests=s; bestx=x;} }\n                edges.push_back({bestx,y});\n            }\n        } else {\n            for (int y: ys) {\n                int bestx=xs[0], bests=-1;\n                for (int x: xs) { int s=score(x,y); if (s>bests){bests=s; bestx=x;} }\n                edges.push_back({bestx,y});\n                covX[bestx]=1; covY[y]=1;\n            }\n            for (int x: xs) if (!covX[x]) {\n                int besty=ys[0], bests=-1;\n                for (int y: ys) { int s=score(x,y); if (s>bests){bests=s; besty=y;} }\n                edges.push_back({x,besty});\n            }\n        }\n\n        vector<vector<uint8_t>> cur(D, vector<uint8_t>(D,0));\n        for (auto [x,y]: edges) {\n            occ[idx3(D,x,y,z)] = 1;\n            cur[x][y]=1;\n        }\n        prev.swap(cur);\n    }\n    return occ;\n}\n\nstatic vector<uint8_t> build_global_matching_edgecover(int D, const SilInfo& si) {\n    vector<vector<int>> w(D, vector<int>(D,0));\n    for (int z=0; z<D; z++) for (int x: si.X[z]) for (int y: si.Y[z]) w[x][y]++;\n\n    int N=D;\n    vector<int> dp(1<<N, -1e9), par(1<<N,-1), parY(1<<N,-1);\n    dp[0]=0;\n    for (int mask=0; mask<(1<<N); mask++) {\n        int i=__builtin_popcount((unsigned)mask);\n        if (i>=N) continue;\n        int cur=dp[mask];\n        if (cur < -1000000) continue;\n        for (int y=0;y<N;y++) if (!(mask&(1<<y))) {\n            int nmask=mask|(1<<y);\n            int val=cur+w[i][y];\n            if (val>dp[nmask]) { dp[nmask]=val; par[nmask]=mask; parY[nmask]=y; }\n        }\n    }\n    vector<int> perm(N,0), inv(N,0);\n    int mask=(1<<N)-1;\n    for (int x=N-1;x>=0;x--) { perm[x]=parY[mask]; mask=par[mask]; }\n    for (int x=0;x<N;x++) inv[perm[x]]=x;\n\n    vector<uint8_t> occ(D*D*D,0);\n\n    auto best_y_for_xz = [&](int x,int z)->int{\n        int besty=si.Y[z][0], bests=-1;\n        for (int y: si.Y[z]) { int s=w[x][y]; if (s>bests){bests=s; besty=y;} }\n        return besty;\n    };\n    auto best_x_for_yz = [&](int y,int z)->int{\n        int bestx=si.X[z][0], bests=-1;\n        for (int x: si.X[z]) { int s=w[x][y]; if (s>bests){bests=s; bestx=x;} }\n        return bestx;\n    };\n\n    for (int z=0; z<D; z++) {\n        for (int x: si.X[z]) {\n            int y=perm[x];\n            if (!si.allow[idx3(D,x,y,z)]) y=best_y_for_xz(x,z);\n            occ[idx3(D,x,y,z)]=1;\n        }\n        for (int y: si.Y[z]) {\n            bool covered=false;\n            for (int x: si.X[z]) if (occ[idx3(D,x,y,z)]) { covered=true; break; }\n            if (covered) continue;\n            int x=inv[y];\n            if (!si.allow[idx3(D,x,y,z)]) x=best_x_for_yz(y,z);\n            occ[idx3(D,x,y,z)]=1;\n        }\n    }\n    return occ;\n}\n\n// ---- improved growth to target (interval-centered fill) ----\nstatic vector<uint8_t> grow_to_target(int D, const SilInfo& si,\n                                      const vector<uint8_t>& base,\n                                      int targetV,\n                                      XorShift& rng) {\n    vector<uint8_t> occ = base;\n    int baseV = (int)volume_of(occ);\n    if (targetV <= baseV) return occ;\n    targetV = min(targetV, si.maxVol);\n    int need = targetV - baseV;\n\n    struct Col { int maxConsec; int baseCnt; int cnt; int x,y; uint64_t tie; };\n    vector<Col> cols;\n    cols.reserve(D*D);\n\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int cnt=0, baseCnt=0, bestRun=0, run=0;\n        for (int z=0; z<D; z++) {\n            int id=idx3(D,x,y,z);\n            if (si.allow[id]) { cnt++; run++; bestRun=max(bestRun,run); }\n            else run=0;\n            if (base[id]) baseCnt++;\n        }\n        if (cnt>0) cols.push_back({bestRun, baseCnt, cnt, x, y, rng.next_u64()});\n    }\n    sort(cols.begin(), cols.end(), [&](const Col& a, const Col& b){\n        if (a.maxConsec!=b.maxConsec) return a.maxConsec>b.maxConsec;\n        if (a.baseCnt!=b.baseCnt) return a.baseCnt>b.baseCnt;\n        if (a.cnt!=b.cnt) return a.cnt>b.cnt;\n        return a.tie<b.tie;\n    });\n\n    vector<uint8_t> allowZ(D), occZ(D);\n\n    for (auto &c : cols) {\n        if (!need) break;\n\n        for (int z=0; z<D; z++) {\n            int id = idx3(D,c.x,c.y,z);\n            allowZ[z] = si.allow[id];\n            occZ[z]   = occ[id];\n        }\n\n        struct Interval { int l,r; int prio; int len; int center; };\n        vector<Interval> ivs;\n\n        for (int z=0; z<D; ) {\n            while (z<D && !allowZ[z]) z++;\n            if (z>=D) break;\n            int l=z;\n            while (z<D && allowZ[z]) z++;\n            int r=z-1;\n\n            int center=(l+r)/2;\n            int prio=0;\n            for (int t=l;t<=r;t++) if (occZ[t]) { prio=1; center=t; break; }\n            ivs.push_back({l,r,prio,r-l+1,center});\n        }\n\n        sort(ivs.begin(), ivs.end(), [&](const Interval& a, const Interval& b){\n            if (a.prio != b.prio) return a.prio > b.prio;\n            if (a.len != b.len) return a.len > b.len;\n            return a.center < b.center;\n        });\n\n        for (auto &iv : ivs) {\n            if (!need) break;\n            for (int d=0; d<=iv.r-iv.l && need; d++) {\n                int z1 = iv.center - d;\n                int z2 = iv.center + d;\n                if (d==0) {\n                    if (z1>=iv.l && z1<=iv.r) {\n                        int id=idx3(D,c.x,c.y,z1);\n                        if (si.allow[id] && !occ[id]) { occ[id]=1; occZ[z1]=1; need--; }\n                    }\n                } else {\n                    if (z1>=iv.l && z1<=iv.r) {\n                        int id=idx3(D,c.x,c.y,z1);\n                        if (si.allow[id] && !occ[id]) { occ[id]=1; occZ[z1]=1; need--; if (!need) break; }\n                    }\n                    if (z2>=iv.l && z2<=iv.r) {\n                        int id=idx3(D,c.x,c.y,z2);\n                        if (si.allow[id] && !occ[id]) { occ[id]=1; occZ[z2]=1; need--; }\n                    }\n                }\n            }\n        }\n    }\n\n    return occ;\n}\n\n// ---- partition building ----\nstatic vector<Segment> extract_segments_axis(int D, const vector<uint8_t>& occ, int axis) {\n    vector<Segment> segs;\n    if (axis==0) {\n        for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n            int x=0;\n            while (x<D) {\n                while (x<D && !occ[idx3(D,x,y,z)]) x++;\n                int s=x;\n                while (x<D && occ[idx3(D,x,y,z)]) x++;\n                int len=x-s;\n                if (len) segs.push_back({s,y,z,0,len});\n            }\n        }\n    } else if (axis==1) {\n        for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n            int y=0;\n            while (y<D) {\n                while (y<D && !occ[idx3(D,x,y,z)]) y++;\n                int s=y;\n                while (y<D && occ[idx3(D,x,y,z)]) y++;\n                int len=y-s;\n                if (len) segs.push_back({x,s,z,1,len});\n            }\n        }\n    } else {\n        for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n            int z=0;\n            while (z<D) {\n                while (z<D && !occ[idx3(D,x,y,z)]) z++;\n                int s=z;\n                while (z<D && occ[idx3(D,x,y,z)]) z++;\n                int len=z-s;\n                if (len) segs.push_back({x,y,s,2,len});\n            }\n        }\n    }\n    return segs;\n}\n\nstatic void remove_segment_voxels(int D, vector<uint8_t>& rem, const Segment& sg) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1; else if (sg.axis==1) dy=1; else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x=sg.x+dx*t, y=sg.y+dy*t, z=sg.z+dz*t;\n        rem[idx3(D,x,y,z)] = 0;\n    }\n}\n\nstatic void find_max_segments(int D, const vector<uint8_t>& rem, int &maxLen, vector<Segment>& best) {\n    maxLen=0; best.clear();\n    auto consider = [&](int x,int y,int z,int axis,int len){\n        if (len<=0) return;\n        if (len>maxLen) { maxLen=len; best.clear(); }\n        if (len==maxLen) best.push_back({x,y,z,axis,len});\n    };\n    for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n        int x=0;\n        while (x<D) {\n            while (x<D && !rem[idx3(D,x,y,z)]) x++;\n            int s=x;\n            while (x<D && rem[idx3(D,x,y,z)]) x++;\n            consider(s,y,z,0,x-s);\n        }\n    }\n    for (int x=0;x<D;x++) for (int z=0;z<D;z++) {\n        int y=0;\n        while (y<D) {\n            while (y<D && !rem[idx3(D,x,y,z)]) y++;\n            int s=y;\n            while (y<D && rem[idx3(D,x,y,z)]) y++;\n            consider(x,s,z,1,y-s);\n        }\n    }\n    for (int x=0;x<D;x++) for (int y=0;y<D;y++) {\n        int z=0;\n        while (z<D) {\n            while (z<D && !rem[idx3(D,x,y,z)]) z++;\n            int s=z;\n            while (z<D && rem[idx3(D,x,y,z)]) z++;\n            consider(x,y,s,2,z-s);\n        }\n    }\n}\n\nstatic vector<Segment> partition_mixed(int D, const vector<uint8_t>& occ, array<int,3> axisBias, XorShift& rng) {\n    vector<uint8_t> rem = occ;\n    vector<Segment> res;\n    res.reserve((int)volume_of(occ));\n    while (true) {\n        bool any=false;\n        for (auto v: rem) if (v) { any=true; break; }\n        if (!any) break;\n        int maxLen; vector<Segment> best;\n        find_max_segments(D, rem, maxLen, best);\n        if (maxLen<=0 || best.empty()) break;\n\n        long long tot=0;\n        for (auto &s: best) tot += axisBias[s.axis];\n        long long r = (long long)(rng.next_u64() % (uint64_t)tot);\n        int pick=0;\n        for (int i=0;i<(int)best.size();i++) {\n            r -= axisBias[best[i].axis];\n            if (r<0) { pick=i; break; }\n        }\n        Segment chosen = best[pick];\n        res.push_back(chosen);\n        remove_segment_voxels(D, rem, chosen);\n    }\n    return res;\n}\n\nstruct PartSet {\n    vector<vector<Segment>> parts;\n    vector<int> cap;\n};\n\nstatic PartSet precompute_partitions(int D, const vector<uint8_t>& occ, uint64_t seedBase) {\n    PartSet ps;\n    ps.parts.reserve(7);\n    ps.cap.reserve(7);\n    auto add_variant = [&](vector<Segment> segs) {\n        int c=1;\n        for (auto &s: segs) c=max(c,s.len);\n        ps.parts.push_back(move(segs));\n        ps.cap.push_back(c);\n    };\n    add_variant(extract_segments_axis(D, occ, 0));\n    add_variant(extract_segments_axis(D, occ, 1));\n    add_variant(extract_segments_axis(D, occ, 2));\n    { XorShift rr(seedBase ^ 0x9e3779b97f4a7c15ULL); add_variant(partition_mixed(D, occ, {1,1,3}, rr)); }\n    { XorShift rr(seedBase ^ 0xbf58476d1ce4e5b9ULL); add_variant(partition_mixed(D, occ, {3,1,1}, rr)); }\n    { XorShift rr(seedBase ^ 0x94d049bb133111ebULL); add_variant(partition_mixed(D, occ, {1,3,1}, rr)); }\n    { XorShift rr(seedBase ^ 0xd6e8feb86659fd93ULL); add_variant(partition_mixed(D, occ, {1,1,1}, rr)); }\n    return ps;\n}\n\n// ---- split pieces optimally to cap ----\nstatic void split_segment_optimal_to_cap(const Segment& sg, int cap, vector<Segment>& out) {\n    if (sg.len <= cap) { out.push_back(sg); return; }\n    int L=sg.len;\n    int m=(L + cap - 1) / cap;\n    int a=L / m;\n    int rem=L % m;\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1; else if (sg.axis==1) dy=1; else dz=1;\n    int off=0;\n    for (int i=0;i<m;i++) {\n        int len=a + (i<rem?1:0);\n        Segment p=sg;\n        p.x += dx*off; p.y += dy*off; p.z += dz*off;\n        p.len=len;\n        out.push_back(p);\n        off += len;\n    }\n}\nstatic void presplit_optimal_to_cap(vector<Segment>& pieces, int cap) {\n    vector<Segment> out;\n    out.reserve(pieces.size()*2);\n    for (auto &sg: pieces) split_segment_optimal_to_cap(sg, cap, out);\n    pieces.swap(out);\n}\n\nstatic bool split_one_piece_balanced(vector<Segment>& pieces, int targetLen, int cap) {\n    int pos=-1;\n    for (int i=0;i<(int)pieces.size();i++) if (pieces[i].len==targetLen && pieces[i].len>=2) { pos=i; break; }\n    if (pos==-1) {\n        int best=-1;\n        for (int i=0;i<(int)pieces.size();i++) if (pieces[i].len>=2) {\n            if (best==-1 || pieces[i].len > pieces[best].len) best=i;\n        }\n        pos=best;\n    }\n    if (pos==-1) return false;\n\n    Segment orig=pieces[pos];\n    int L=orig.len;\n    if (L<2) return false;\n\n    int a=L/2, b=L-a;\n    if (a>cap || b>cap) {\n        int m=(L+cap-1)/cap;\n        int base=L/m, rem=L%m;\n        int part=min(cap, base + (rem?1:0));\n        a=part; b=L-a;\n        if (b<=0) return false;\n        if (b>cap) { a=cap; b=L-cap; }\n    }\n\n    Segment s1=orig; s1.len=a;\n    Segment s2=orig; s2.len=b;\n    if (orig.axis==0) s2.x += a;\n    else if (orig.axis==1) s2.y += a;\n    else s2.z += a;\n\n    pieces[pos]=s1;\n    pieces.push_back(s2);\n    return true;\n}\n\nstatic long double penalty_sum_inv(const vector<Segment>& pieces) {\n    long double s=0;\n    for (auto &p: pieces) s += 1.0L / (long double)p.len;\n    return s;\n}\n\nstatic long double penalty_lb(int vSmall, int cap) {\n    cap = max(1, cap);\n    int q = vSmall / cap;\n    int r = vSmall % cap;\n    long double lb = (long double)q * (1.0L/(long double)cap);\n    if (r) lb += 1.0L/(long double)r;\n    return lb;\n}\n\n// ---- packing into disjoint bins, fragmentation-aware cap choice (soft) ----\nstruct PackResult {\n    bool ok=false;\n    int failLen=0;\n    vector<Segment> placed; // per piece\n    vector<int> usedOff;\n    vector<int> remLen;\n};\n\nstatic int score_leftover(int s) {\n    if (s==0) return 0;\n    int sc = 0;\n    if (s==1) sc += 100000;\n    if (s==2) sc += 2000;\n    sc += 10 * s;\n    return sc;\n}\n\nstatic int choose_cap_for_piece_soft(int L, const vector<vector<int>>& bucket, int D, XorShift& rng) {\n    int bestSc = INT_MAX;\n    for (int c=L; c<=D; c++) if (!bucket[c].empty()) bestSc = min(bestSc, score_leftover(c-L));\n    if (bestSc==INT_MAX) return -1;\n\n    const int DELTA = 40; // allow near-best choices to diversify\n    vector<int> caps;\n    vector<int> w;\n    int sumW = 0;\n    for (int c=L; c<=D; c++) if (!bucket[c].empty()) {\n        int sc = score_leftover(c-L);\n        if (sc <= bestSc + DELTA) {\n            caps.push_back(c);\n            // weight = 1 / (1 + sc-bestSc) scaled\n            int ww = 100 / (1 + (sc - bestSc));\n            ww = max(1, ww);\n            w.push_back(ww);\n            sumW += ww;\n        }\n    }\n    if (caps.empty()) return -1;\n    int r = rng.next_int(sumW);\n    for (int i=0;i<(int)caps.size();i++) {\n        r -= w[i];\n        if (r < 0) return caps[i];\n    }\n    return caps.back();\n}\n\nstatic PackResult pack_pieces_into_bins_once(int D,\n                                            const vector<Segment>& bins,\n                                            const vector<Segment>& pieces,\n                                            XorShift& rng) {\n    PackResult pr;\n    int B=(int)bins.size();\n    int P=(int)pieces.size();\n    pr.placed.assign(P, {0,0,0,0,0});\n    pr.usedOff.assign(B, 0);\n    pr.remLen.assign(B, 0);\n\n    vector<vector<int>> bucket(D+1);\n    for (int i=0;i<B;i++) {\n        pr.remLen[i] = bins[i].len;\n        bucket[bins[i].len].push_back(i);\n    }\n\n    vector<vector<int>> piecesByLen(D+1);\n    for (int i=0;i<P;i++) piecesByLen[pieces[i].len].push_back(i);\n\n    for (int L=D; L>=1; L--) {\n        auto &vecP = piecesByLen[L];\n        for (int t=0;t<(int)vecP.size();t++) {\n            int sw = t + rng.next_int((int)vecP.size()-t);\n            swap(vecP[t], vecP[sw]);\n        }\n        for (int pi : vecP) {\n            int c = choose_cap_for_piece_soft(L, bucket, D, rng);\n            if (c==-1) { pr.ok=false; pr.failLen=L; return pr; }\n\n            auto &vecB = bucket[c];\n            int idx = rng.next_int((int)vecB.size());\n            int binId = vecB[idx];\n            vecB[idx] = vecB.back();\n            vecB.pop_back();\n\n            Segment base = bins[binId];\n            int used = pr.usedOff[binId];\n            int dx=0,dy=0,dz=0;\n            if (base.axis==0) dx=1; else if (base.axis==1) dy=1; else dz=1;\n\n            Segment place = base;\n            place.x += dx*used; place.y += dy*used; place.z += dz*used;\n            place.len = L;\n            pr.placed[pi] = place;\n\n            pr.usedOff[binId] += L;\n            int rem = c - L;\n            pr.remLen[binId] = rem;\n            if (rem > 0) bucket[rem].push_back(binId);\n        }\n    }\n\n    pr.ok=true; pr.failLen=0;\n    return pr;\n}\n\nstatic PackResult pack_pieces_into_bins_retry(int D,\n                                             const vector<Segment>& bins,\n                                             const vector<Segment>& pieces,\n                                             XorShift& rng,\n                                             int retries) {\n    int worstFail = 0;\n    for (int t=0;t<retries;t++) {\n        XorShift rr(rng.next_u64());\n        auto pr = pack_pieces_into_bins_once(D, bins, pieces, rr);\n        if (pr.ok) return pr;\n        worstFail = max(worstFail, pr.failLen);\n    }\n    PackResult ret;\n    ret.ok = false;\n    ret.failLen = worstFail;\n    return ret;\n}\n\nstatic void fill_segment_id(int D, vector<int>& b, const Segment& sg, int id) {\n    int dx=0,dy=0,dz=0;\n    if (sg.axis==0) dx=1; else if (sg.axis==1) dy=1; else dz=1;\n    for (int t=0;t<sg.len;t++) {\n        int x=sg.x+dx*t, y=sg.y+dy*t, z=sg.z+dz*t;\n        b[idx3(D,x,y,z)] = id;\n    }\n}\n\n// ---- candidate + partitions ----\nstruct Cand {\n    vector<uint8_t> occ;\n    int vol;\n    uint64_t h;\n    PartSet ps;\n};\n\nstatic vector<Cand> gen_candidates(int D, const SilInfo& si, XorShift& rng) {\n    vector<pair<vector<uint8_t>, int>> raw;\n    unordered_set<uint64_t> seen;\n\n    auto add_occ = [&](vector<uint8_t> occ) {\n        uint64_t h = hash_occ(occ);\n        if (!seen.insert(h).second) return;\n        int v = (int)volume_of(occ);\n        raw.push_back({move(occ), v});\n    };\n\n    auto occMin   = build_min_edgecover(D, si);\n    auto occCont  = build_continuity_edgecover(D, si);\n    auto occMatch = build_global_matching_edgecover(D, si);\n    auto occStar  = build_star_stable(D, si);\n    auto occGStar = build_star_globalhub(D, si);\n    auto occDense = build_dense(D, si);\n\n    add_occ(occMin); add_occ(occCont); add_occ(occMatch);\n    add_occ(occStar); add_occ(occGStar); add_occ(occDense);\n\n    int minV = (int)volume_of(occMin);\n    int maxV = si.maxVol;\n\n    vector<vector<uint8_t>> bases = {occMin, occCont, occMatch, occStar};\n    vector<double> ratios = {0.20,0.35,0.50,0.65,0.80,0.92,0.97};\n\n    for (auto &base : bases) {\n        int baseV = (int)volume_of(base);\n        for (double rr : ratios) {\n            int target = minV + (int)llround((maxV - minV) * rr);\n            target = max(target, baseV);\n            XorShift rrng(rng.next_u64() ^ (uint64_t)(target*2654435761u + baseV*97531u));\n            add_occ(grow_to_target(D, si, base, target, rrng));\n        }\n    }\n\n    sort(raw.begin(), raw.end(), [&](auto &a, auto &b){ return a.second < b.second; });\n\n    const int KEEP = 22;\n    vector<pair<vector<uint8_t>, int>> picked;\n    picked.reserve(KEEP+4);\n    for (int t=0;t<KEEP;t++) {\n        int desired = minV + (int)llround((long double)(maxV-minV) * t / max(1, KEEP-1));\n        int best=-1, bestDist=INT_MAX;\n        for (int i=0;i<(int)raw.size();i++) {\n            int dist = abs(raw[i].second - desired);\n            if (dist < bestDist) { bestDist=dist; best=i; }\n        }\n        if (best!=-1) picked.push_back(raw[best]);\n    }\n    picked.push_back({occMin, minV});\n    picked.push_back({occDense, maxV});\n\n    vector<Cand> res;\n    unordered_set<uint64_t> seen2;\n    for (auto &p : picked) {\n        uint64_t h = hash_occ(p.first);\n        if (!seen2.insert(h).second) continue;\n        Cand c;\n        c.occ = move(p.first);\n        c.vol = p.second;\n        c.h = h;\n        c.ps = precompute_partitions(D, c.occ, h ^ 0x123456789abcdefULL);\n        res.push_back(move(c));\n    }\n    sort(res.begin(), res.end(), [&](const Cand& a, const Cand& b){ return a.vol < b.vol; });\n    return res;\n}\n\n// ---- partition cache for grown variants ----\nstruct PartCacheEntry { int vol; PartSet ps; };\n\nstatic PartCacheEntry build_cache_entry(int D, const vector<uint8_t>& occ) {\n    PartCacheEntry e;\n    e.vol = (int)volume_of(occ);\n    uint64_t h = hash_occ(occ);\n    e.ps = precompute_partitions(D, occ, h ^ 0x123456789abcdefULL);\n    return e;\n}\n\n// ---- solve fixed occ pair ----\nstruct BestPlan {\n    long double cost = 1e100L;\n    int smallObj=-1;\n    vector<uint8_t> occ0, occ1;\n    vector<Segment> piecesSmall;\n    vector<Segment> placedLarge;\n    vector<Segment> uniqueLarge;\n};\n\nstatic BestPlan solve_occ_pair_fast(const Timer& timer, double deadline,\n                                   int D,\n                                   const vector<uint8_t>& occ0, int v0, const PartSet& ps0,\n                                   const vector<uint8_t>& occ1, int v1, const PartSet& ps1,\n                                   XorShift& rng,\n                                   long double currentBest) {\n    BestPlan best;\n    int smallObj = (v0 <= v1 ? 0 : 1);\n    int diff = abs(v0 - v1);\n    int vSmall = min(v0, v1);\n\n    if ((long double)diff >= currentBest) return best;\n\n    const PartSet& psSmall = (smallObj==0 ? ps0 : ps1);\n    const PartSet& psLarge = (smallObj==0 ? ps1 : ps0);\n\n    for (int lv=0; lv<(int)psLarge.parts.size(); lv++) {\n        if (timer.elapsed() > deadline) break;\n        const auto& bins = psLarge.parts[lv];\n        int cap = max(1, psLarge.cap[lv]);\n\n        if ((long double)diff + penalty_lb(vSmall, cap) >= currentBest) continue;\n\n        for (int sv=0; sv<(int)psSmall.parts.size(); sv++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Segment> pieces = psSmall.parts[sv];\n            presplit_optimal_to_cap(pieces, cap);\n\n            int splitCnt=0;\n            while (timer.elapsed() <= deadline) {\n                PackResult pr = pack_pieces_into_bins_retry(D, bins, pieces, rng, 7);\n                if (pr.ok) {\n                    vector<Segment> uniq;\n                    uniq.reserve(bins.size());\n                    for (int bi=0; bi<(int)bins.size(); bi++) {\n                        int rem = pr.remLen[bi];\n                        if (rem <= 0) continue;\n                        Segment base = bins[bi];\n                        int used = pr.usedOff[bi];\n                        int dx=0,dy=0,dz=0;\n                        if (base.axis==0) dx=1; else if (base.axis==1) dy=1; else dz=1;\n                        Segment tail = base;\n                        tail.x += dx*used; tail.y += dy*used; tail.z += dz*used;\n                        tail.len = rem;\n                        uniq.push_back(tail);\n                    }\n\n                    long double pen = penalty_sum_inv(pieces);\n                    long double cost = (long double)diff + pen;\n                    if (cost < best.cost) {\n                        best.cost = cost;\n                        best.smallObj = smallObj;\n                        best.occ0 = occ0; best.occ1 = occ1;\n                        best.piecesSmall = move(pieces);\n                        best.placedLarge = move(pr.placed);\n                        best.uniqueLarge = move(uniq);\n                    }\n                    break;\n                } else {\n                    if (pr.failLen <= 1) break;\n                    if (!split_one_piece_balanced(pieces, pr.failLen, cap)) break;\n                    if (++splitCnt > 420) break;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n    vector<string> f[2], r[2];\n    for (int i=0;i<2;i++) {\n        f[i].resize(D);\n        r[i].resize(D);\n        for (int z=0;z<D;z++) cin >> f[i][z];\n        for (int z=0;z<D;z++) cin >> r[i][z];\n    }\n\n    Timer timer;\n    const double DEADLINE = 5.45;\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)D; seed *= 1099511628211ull;\n    for (int i=0;i<2;i++) {\n        for (int z=0;z<D;z++) seed = fnv1a64(f[i][z], seed);\n        for (int z=0;z<D;z++) seed = fnv1a64(r[i][z], seed);\n    }\n    XorShift rng(seed);\n\n    SilInfo si[2] = { build_allow(D,f[0],r[0]), build_allow(D,f[1],r[1]) };\n    auto C0 = gen_candidates(D, si[0], rng);\n    auto C1 = gen_candidates(D, si[1], rng);\n\n    struct PairInfo { int i,j,diff; };\n    vector<PairInfo> pairs;\n    pairs.reserve(C0.size()*C1.size());\n    for (int i=0;i<(int)C0.size();i++) for (int j=0;j<(int)C1.size();j++) {\n        pairs.push_back({i,j, abs(C0[i].vol - C1[j].vol)});\n    }\n    sort(pairs.begin(), pairs.end(), [&](const PairInfo& a, const PairInfo& b){ return a.diff < b.diff; });\n\n    BestPlan best;\n\n    unordered_map<uint64_t, PartCacheEntry> partCache;\n    partCache.reserve(256);\n\n    auto get_cached = [&](const vector<uint8_t>& occ) -> PartCacheEntry& {\n        uint64_t h = hash_occ(occ);\n        auto it = partCache.find(h);\n        if (it != partCache.end()) return it->second;\n        auto entry = build_cache_entry(D, occ);\n        auto [it2, ok] = partCache.emplace(h, move(entry));\n        return it2->second;\n    };\n\n    auto consider_variant = [&](const vector<uint8_t>& o0, const vector<uint8_t>& o1) {\n        if (timer.elapsed() > DEADLINE) return;\n        auto &e0 = get_cached(o0);\n        auto &e1 = get_cached(o1);\n        auto bp = solve_occ_pair_fast(timer, DEADLINE, D, o0, e0.vol, e0.ps, o1, e1.vol, e1.ps, rng, best.cost);\n        if (bp.smallObj != -1 && bp.cost < best.cost) best = move(bp);\n    };\n\n    int PAIR_LIMIT = 185;\n    int Vcommon = min(si[0].maxVol, si[1].maxVol);\n\n    for (int k=0;k<(int)pairs.size() && k<PAIR_LIMIT && timer.elapsed()<=DEADLINE;k++) {\n        int i=pairs[k].i, j=pairs[k].j;\n        if ((long double)pairs[k].diff >= best.cost) break;\n\n        const auto& base0 = C0[i].occ;\n        const auto& base1 = C1[j].occ;\n        int v0 = C0[i].vol, v1 = C1[j].vol;\n\n        consider_variant(base0, base1);\n        if (timer.elapsed() > DEADLINE) break;\n\n        // Grow smaller to match larger volume\n        if (pairs[k].diff <= 3*D*D) {\n            if (v0 < v1 && v1 <= si[0].maxVol) {\n                XorShift rr(rng.next_u64());\n                consider_variant(grow_to_target(D, si[0], base0, v1, rr), base1);\n            } else if (v1 < v0 && v0 <= si[1].maxVol) {\n                XorShift rr(rng.next_u64());\n                consider_variant(base0, grow_to_target(D, si[1], base1, v0, rr));\n            }\n        }\n        if (timer.elapsed() > DEADLINE) break;\n\n        // Mid common volume growth (limited)\n        if (k < 70 && pairs[k].diff <= 4*D*D && Vcommon > max(v0,v1)) {\n            int maxv = max(v0,v1);\n            int Vmid = maxv + (Vcommon - maxv) / 2;\n            XorShift rr0(rng.next_u64()), rr1(rng.next_u64());\n            consider_variant(grow_to_target(D, si[0], base0, Vmid, rr0),\n                             grow_to_target(D, si[1], base1, Vmid, rr1));\n        }\n        if (timer.elapsed() > DEADLINE) break;\n\n        // Grow both to common max for top very small-diff pairs\n        if (k < 26 && pairs[k].diff <= D*D && Vcommon > 0) {\n            XorShift rr0(rng.next_u64()), rr1(rng.next_u64());\n            consider_variant(grow_to_target(D, si[0], base0, Vcommon, rr0),\n                             grow_to_target(D, si[1], base1, Vcommon, rr1));\n        }\n    }\n\n    // Fallback: dense + unit cubes\n    if (best.smallObj == -1) {\n        vector<int> b0(D*D*D,0), b1(D*D*D,0);\n        int n=0;\n        for (int i=0;i<2;i++) {\n            const auto& A = si[i].allow;\n            for (int x=0;x<D;x++) for (int y=0;y<D;y++) for (int z=0;z<D;z++) {\n                int id=idx3(D,x,y,z);\n                if (A[id]) { n++; if (i==0) b0[id]=n; else b1[id]=n; }\n            }\n        }\n        cout << n << \"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b0[i]; } cout<<\"\\n\";\n        for (int i=0;i<D*D*D;i++){ if(i) cout<<' '; cout<<b1[i]; } cout<<\"\\n\";\n        return 0;\n    }\n\n    // Output labeling\n    vector<int> out0(D*D*D,0), out1(D*D*D,0);\n    int smallObj = best.smallObj;\n    int largeObj = 1-smallObj;\n\n    int m = (int)best.piecesSmall.size();\n    int u = (int)best.uniqueLarge.size();\n    int n = m + u;\n\n    int curId=1;\n    for (int i=0;i<m;i++,curId++) {\n        if (smallObj==0) {\n            fill_segment_id(D, out0, best.piecesSmall[i], curId);\n            fill_segment_id(D, out1, best.placedLarge[i], curId);\n        } else {\n            fill_segment_id(D, out1, best.piecesSmall[i], curId);\n            fill_segment_id(D, out0, best.placedLarge[i], curId);\n        }\n    }\n    for (int i=0;i<u;i++,curId++) {\n        if (largeObj==0) fill_segment_id(D, out0, best.uniqueLarge[i], curId);\n        else fill_segment_id(D, out1, best.uniqueLarge[i], curId);\n    }\n\n    cout << n << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << out0[i]; }\n    cout << \"\\n\";\n    for (int i=0;i<D*D*D;i++) { if (i) cout << ' '; cout << out1[i]; }\n    cout << \"\\n\";\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Edge { int u, v; long long w; };\n\nstatic inline int ceil_sqrt_ll(long long x) {\n    if (x <= 0) return 0;\n    long long r = (long long)floor(sqrt((long double)x));\n    while (r * r < x) ++r;\n    while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n    return (int)r;\n}\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n=0): n(n), p(n), sz(n,1) { iota(p.begin(), p.end(), 0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool merge(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(sz[a]<sz[b]) swap(a,b);\n        p[b]=a; sz[a]+=sz[b];\n        return true;\n    }\n};\n\n// xorshift64 RNG\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed=88172645463325252ull): x(seed) {}\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Connector {\n    int N, M;\n    vector<Edge> edges;\n    vector<vector<tuple<int,long long,int>>> g; // to, w, edgeId\n\n    vector<vector<long long>> dist;\n    vector<vector<int>> prevV, prevE;\n\n    vector<int> usedStamp;\n    int stamp = 1;\n\n    vector<int> remStamp;\n    int remCurStamp = 1;\n\n    Connector(int N_, int M_, const vector<Edge>& e): N(N_), M(M_), edges(e),\n        g(N), dist(N, vector<long long>(N, (1LL<<62))),\n        prevV(N, vector<int>(N, -1)), prevE(N, vector<int>(N, -1)),\n        usedStamp(M, 0), remStamp(M, 0) {\n\n        for (int i = 0; i < M; i++) {\n            g[edges[i].u].push_back({edges[i].v, edges[i].w, i});\n            g[edges[i].v].push_back({edges[i].u, edges[i].w, i});\n        }\n        all_pairs_dijkstra();\n    }\n\n    void all_pairs_dijkstra() {\n        for (int s = 0; s < N; s++) {\n            auto &ds = dist[s];\n            auto &pv = prevV[s];\n            auto &pe = prevE[s];\n            fill(ds.begin(), ds.end(), (1LL<<62));\n            fill(pv.begin(), pv.end(), -1);\n            fill(pe.begin(), pe.end(), -1);\n            using P = pair<long long,int>;\n            priority_queue<P, vector<P>, greater<P>> pq;\n            ds[s] = 0; pv[s] = s; pe[s] = -1;\n            pq.push({0, s});\n            while (!pq.empty()) {\n                auto [dcur, v] = pq.top(); pq.pop();\n                if (dcur != ds[v]) continue;\n                for (auto [to, w, id] : g[v]) {\n                    long long nd = dcur + w;\n                    if (nd < ds[to]) {\n                        ds[to] = nd;\n                        pv[to] = v;\n                        pe[to] = id;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n        }\n    }\n\n    // Candidate edges from metric MST expansion\n    vector<int> candidate_metric_mst(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n\n        if ((int)terminals.size() <= 1) return marked;\n\n        int T = (int)terminals.size();\n        const long long INF = (1LL<<62);\n        vector<long long> key(T, INF);\n        vector<int> parent(T, -1);\n        vector<char> inMST(T, false);\n        key[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1; long long best = INF;\n            for (int i = 0; i < T; i++) if (!inMST[i] && key[i] < best) {\n                best = key[i]; v = i;\n            }\n            if (v == -1) break;\n            inMST[v] = true;\n            int tv = terminals[v];\n            for (int u = 0; u < T; u++) if (!inMST[u]) {\n                int tu = terminals[u];\n                long long d = dist[tv][tu];\n                if (d < key[u]) { key[u] = d; parent[u] = v; }\n            }\n        }\n\n        for (int i = 1; i < T; i++) {\n            int a = terminals[i];\n            int b = terminals[parent[i]];\n            int cur = b;\n            while (cur != a) {\n                int eid = prevE[a][cur];\n                int pvv = prevV[a][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        // ensure terminal reachability from 0 if something is missing\n        vector<char> reach(N, false);\n        deque<int> dq;\n        reach[0] = true; dq.push_back(0);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (auto [to, w, id] : g[v]) {\n                if (usedStamp[id] != curStamp) continue;\n                if (!reach[to]) { reach[to] = true; dq.push_back(to); }\n            }\n        }\n        for (int t : terminals) if (!reach[t]) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n\n        return marked;\n    }\n\n    // Candidate edges from union of shortest paths from 0\n    vector<int> candidate_root_paths(const vector<int>& terminals) {\n        int curStamp = stamp++;\n        vector<int> marked; marked.reserve(M);\n        auto mark_edge = [&](int eid) {\n            if (usedStamp[eid] != curStamp) {\n                usedStamp[eid] = curStamp;\n                marked.push_back(eid);\n            }\n        };\n        for (int t : terminals) if (t != 0) {\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevE[0][cur];\n                int pvv = prevV[0][cur];\n                if (eid < 0 || pvv < 0) break;\n                mark_edge(eid);\n                cur = pvv;\n            }\n        }\n        return marked;\n    }\n\n    pair<long long, vector<int>> prune_candidate(const vector<int>& cand, const vector<char>& isTerm, bool needEdges) {\n        if (cand.empty()) return {0LL, {}};\n\n        vector<int> candSorted = cand;\n        sort(candSorted.begin(), candSorted.end(),\n             [&](int a, int b){ return edges[a].w < edges[b].w; });\n\n        DSU dsu(N);\n        vector<int> treeEdges; treeEdges.reserve(candSorted.size());\n        for (int eid : candSorted) if (dsu.merge(edges[eid].u, edges[eid].v)) treeEdges.push_back(eid);\n\n        vector<vector<pair<int,int>>> adj(N);\n        vector<int> deg(N, 0);\n        for (int eid : treeEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            adj[u].push_back({v, eid});\n            adj[v].push_back({u, eid});\n            deg[u]++; deg[v]++;\n        }\n\n        int curRemStamp = remCurStamp++;\n        auto isRemoved = [&](int eid)->bool { return remStamp[eid] == curRemStamp; };\n        auto setRemoved = [&](int eid){ remStamp[eid] = curRemStamp; };\n\n        deque<int> q;\n        for (int i = 0; i < N; i++) if (!isTerm[i] && deg[i] == 1) q.push_back(i);\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n            int to = -1, eid = -1;\n            for (auto [nx, id] : adj[v]) if (!isRemoved(id)) { to = nx; eid = id; break; }\n            if (eid == -1) { deg[v] = 0; continue; }\n            setRemoved(eid);\n            deg[v]--; deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        long long cost = 0;\n        vector<int> remain;\n        if (needEdges) remain.reserve(treeEdges.size());\n        for (int eid : treeEdges) if (!isRemoved(eid)) {\n            cost += edges[eid].w;\n            if (needEdges) remain.push_back(eid);\n        }\n        return {cost, remain};\n    }\n\n    // Fast cost used inside SA: metric MST expansion only\n    long long steiner_cost_metric(const vector<int>& terminals) {\n        if (terminals.size() <= 1) return 0;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        auto cand = candidate_metric_mst(terminals);\n        return prune_candidate(cand, isTerm, false).first;\n    }\n\n    // Final build: choose better of metric MST vs root-path union\n    vector<char> steiner_build_best(const vector<int>& terminals) {\n        vector<char> on(M, 0);\n        if (terminals.size() <= 1) return on;\n        vector<char> isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n\n        auto candA = candidate_metric_mst(terminals);\n        auto resA = prune_candidate(candA, isTerm, true);\n\n        auto candB = candidate_root_paths(terminals);\n        auto resB = prune_candidate(candB, isTerm, true);\n\n        const auto& best = (resA.first <= resB.first) ? resA : resB;\n        for (int eid : best.second) on[eid] = 1;\n        return on;\n    }\n};\n\nstruct KeyMask {\n    uint64_t a, b;\n    bool operator==(const KeyMask& o) const { return a==o.a && b==o.b; }\n};\nstruct KeyHash {\n    size_t operator()(const KeyMask& k) const {\n        uint64_t x = k.a * 11995408973635179863ULL ^ (k.b + 0x9e3779b97f4a7c15ULL);\n        x ^= x >> 33; x *= 0xff51afd7ed558ccdULL;\n        x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53ULL;\n        x ^= x >> 33;\n        return (size_t)x;\n    }\n};\n\nstruct SAState {\n    int N, K;\n    const vector<int>* dist2;                // K*N\n    const vector<array<int,100>>* order;     // K\n    Connector* conn;\n    unordered_map<KeyMask, long long, KeyHash>* edgeCache;\n\n    static constexpr int D2_LIMIT = 5000 * 5000;\n\n    vector<char> active;\n    vector<int> owner;\n    vector<int> dOwn;\n\n    vector<int> head;\n    vector<int> rprev, rnext;\n\n    vector<multiset<int>> ms;\n    vector<int> P;\n\n    long long radioCost = 0;\n    long long edgeCost = 0;\n    long long totalCost = 0;\n\n    inline int d2(int k, int i) const { return (*dist2)[k*N + i]; }\n\n    void list_remove(int k) {\n        int s = owner[k];\n        int pv = rprev[k], nx = rnext[k];\n        if (pv != -1) rnext[pv] = nx;\n        else head[s] = nx;\n        if (nx != -1) rprev[nx] = pv;\n        rprev[k] = rnext[k] = -1;\n    }\n    void list_add(int k, int s) {\n        int h = head[s];\n        head[s] = k;\n        rprev[k] = -1;\n        rnext[k] = h;\n        if (h != -1) rprev[h] = k;\n    }\n\n    vector<int> terminals() const {\n        vector<int> t; t.reserve(N);\n        t.push_back(0);\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) t.push_back(i);\n        return t;\n    }\n\n    KeyMask terminal_mask() const {\n        uint64_t a=0, b=0;\n        // include 0 always\n        a |= 1ULL;\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) {\n            if (i < 64) a |= 1ULL << i;\n            else b |= 1ULL << (i - 64);\n        }\n        return {a,b};\n    }\n\n    long long edge_cost_cached() {\n        KeyMask km = terminal_mask();\n        auto it = edgeCache->find(km);\n        if (it != edgeCache->end()) return it->second;\n        auto terms = terminals();\n        long long c = conn->steiner_cost_metric(terms);\n        (*edgeCache)[km] = c;\n        return c;\n    }\n\n    int nearest_active(int k, int ex) const {\n        for (int idx = 0; idx < N; idx++) {\n            int v = (*order)[k][idx];\n            if (!active[v]) continue;\n            if (v == ex) continue;\n            int dd = d2(k, v);\n            if (dd <= D2_LIMIT) return v;\n        }\n        return -1;\n    }\n\n    void rebuild_from_active_nearest() {\n        active[0] = 1;\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            for (int idx = 0; idx < N; idx++) {\n                int v = (*order)[k][idx];\n                if (active[v]) { chosen = v; break; }\n            }\n            if (chosen < 0) chosen = 0;\n            int dd = d2(k, chosen);\n            owner[k] = chosen;\n            dOwn[k] = dd;\n            list_add(k, chosen);\n            ms[chosen].insert(dd);\n        }\n\n        for (int i = 1; i < N; i++) if (ms[i].empty()) active[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    void rebuild_from_active_owner(const vector<char>& act, const vector<int>& own) {\n        active = act;\n        active[0] = 1;\n\n        owner.assign(K, 0);\n        dOwn.assign(K, 0);\n        head.assign(N, -1);\n        rprev.assign(K, -1);\n        rnext.assign(K, -1);\n        ms.assign(N, {});\n        P.assign(N, 0);\n        radioCost = 0;\n\n        for (int k = 0; k < K; k++) {\n            int s = own[k];\n            if (s < 0 || s >= N || !active[s] || d2(k, s) > D2_LIMIT) {\n                s = nearest_active(k, -1);\n                if (s < 0) s = 0;\n            }\n            owner[k] = s;\n            int dd = d2(k, s);\n            dOwn[k] = dd;\n            list_add(k, s);\n            ms[s].insert(dd);\n        }\n\n        // make sure non-empty are active\n        for (int i = 1; i < N; i++) if (!ms[i].empty()) active[i] = 1;\n\n        for (int i = 0; i < N; i++) {\n            int p = ms[i].empty() ? 0 : ceil_sqrt_ll(*ms[i].rbegin());\n            if (p > 5000) p = 5000;\n            P[i] = p;\n            radioCost += 1LL * p * p;\n        }\n\n        edgeCost = edge_cost_cached();\n        totalCost = radioCost + edgeCost;\n    }\n\n    struct Log {\n        vector<tuple<int,int,int>> moved; // (resident, oldOwner, oldDist)\n        vector<pair<int,char>> flipped;   // (station, oldActive)\n        vector<pair<int,int>> oldP;       // (station, oldP)\n        vector<pair<int,char>> oldEmpty;  // (station, oldEmpty)\n        vector<int> touched;\n        vector<char> touchedFlag;\n        long long oldRadio, oldEdge, oldTotal;\n        Log(int N=0): touchedFlag(N, 0) {}\n    };\n\n    void touch_station(int s, Log& log) {\n        if (log.touchedFlag[s]) return;\n        log.touchedFlag[s] = 1;\n        log.touched.push_back(s);\n        log.oldP.push_back({s, P[s]});\n        log.oldEmpty.push_back({s, (char)ms[s].empty()});\n    }\n\n    void move_resident(int k, int newS, Log& log) {\n        int oldS = owner[k];\n        if (oldS == newS) return;\n        int oldD = dOwn[k];\n        log.moved.push_back({k, oldS, oldD});\n\n        touch_station(oldS, log);\n        touch_station(newS, log);\n\n        auto it = ms[oldS].find(oldD);\n        if (it != ms[oldS].end()) ms[oldS].erase(it);\n        int nd = d2(k, newS);\n        ms[newS].insert(nd);\n\n        list_remove(k);\n        owner[k] = newS;\n        dOwn[k] = nd;\n        list_add(k, newS);\n    }\n\n    bool apply_remove(int v, Log& log) {\n        if (v == 0 || !active[v]) return false;\n\n        log.flipped.push_back({v, active[v]});\n        active[v] = 0;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n        return true;\n    }\n\n    bool apply_add(int u, Log& log) {\n        if (active[u]) return false;\n        log.flipped.push_back({u, active[u]});\n        active[u] = 1;\n\n        // move residents who prefer u (distance, then index)\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    bool apply_swap(int v, int u, Log& log) {\n        if (v == 0 || !active[v] || active[u]) return false;\n        log.flipped.push_back({v, active[v]}); active[v] = 0;\n        log.flipped.push_back({u, active[u]}); active[u] = 1;\n\n        vector<int> residents;\n        for (int k = head[v]; k != -1; k = rnext[k]) residents.push_back(k);\n        for (int k : residents) {\n            int dest = nearest_active(k, -1);\n            if (dest < 0) return false;\n            move_resident(k, dest, log);\n        }\n\n        for (int k = 0; k < K; k++) {\n            int cur = owner[k];\n            int du = d2(k, u);\n            if (du > D2_LIMIT) continue;\n            int dc = dOwn[k];\n            if (du < dc || (du == dc && u < cur)) move_resident(k, u, log);\n        }\n        return true;\n    }\n\n    void finalize(Log& log) {\n        // update radio incrementally\n        radioCost = log.oldRadio;\n        vector<int> oldpArr(N, -1);\n        vector<char> oldEmptyArr(N, 0);\n        for (auto [s, op] : log.oldP) oldpArr[s] = op;\n        for (auto [s, oe] : log.oldEmpty) oldEmptyArr[s] = oe;\n\n        bool terminalChanged = false;\n        for (int s : log.touched) {\n            int oldp = oldpArr[s];\n            int newp = 0;\n            if (!ms[s].empty()) newp = ceil_sqrt_ll(*ms[s].rbegin());\n            if (newp > 5000) newp = 5000;\n            P[s] = newp;\n            radioCost += 1LL*newp*newp - 1LL*oldp*oldp;\n            if ((bool)oldEmptyArr[s] != ms[s].empty()) terminalChanged = true;\n        }\n\n        if (terminalChanged) edgeCost = edge_cost_cached();\n        else edgeCost = log.oldEdge;\n\n        totalCost = radioCost + edgeCost;\n    }\n\n    void undo(Log& log) {\n        for (int i = (int)log.moved.size() - 1; i >= 0; i--) {\n            auto [k, oldS, oldD] = log.moved[i];\n            int curS = owner[k];\n            int curD = dOwn[k];\n\n            auto it = ms[curS].find(curD);\n            if (it != ms[curS].end()) ms[curS].erase(it);\n            ms[oldS].insert(oldD);\n\n            list_remove(k);\n            owner[k] = oldS;\n            dOwn[k] = oldD;\n            list_add(k, oldS);\n        }\n\n        for (int i = (int)log.flipped.size() - 1; i >= 0; i--) {\n            auto [s, oldA] = log.flipped[i];\n            active[s] = oldA;\n        }\n        for (auto [s, op] : log.oldP) P[s] = op;\n\n        radioCost = log.oldRadio;\n        edgeCost  = log.oldEdge;\n        totalCost = log.oldTotal;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n    vector<int> x(N), y(N);\n    for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n    vector<Edge> edges(M);\n    for (int j = 0; j < M; j++) {\n        int u, v; long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n    }\n\n    vector<int> a(K), b(K);\n    for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n    vector<int> dist2((size_t)K * N);\n    for (int k = 0; k < K; k++) for (int i = 0; i < N; i++) {\n        long long dx = (long long)x[i] - a[k];\n        long long dy = (long long)y[i] - b[k];\n        dist2[k*N + i] = (int)(dx*dx + dy*dy);\n    }\n\n    vector<array<int,100>> order(K);\n    for (int k = 0; k < K; k++) {\n        for (int i = 0; i < N; i++) order[k][i] = i;\n        sort(order[k].begin(), order[k].end(), [&](int i, int j){\n            int di = dist2[k*N + i];\n            int dj = dist2[k*N + j];\n            if (di != dj) return di < dj;\n            return i < j;\n        });\n    }\n\n    Connector conn(N, M, edges);\n\n    unordered_map<KeyMask, long long, KeyHash> edgeCache;\n    edgeCache.reserve(1 << 14);\n\n    SAState st;\n    st.N = N; st.K = K;\n    st.dist2 = &dist2;\n    st.order = &order;\n    st.conn = &conn;\n    st.edgeCache = &edgeCache;\n\n    st.active.assign(N, 1);\n    st.rebuild_from_active_nearest();\n\n    RNG rng(123456789);\n    auto start = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n    const double TL = 1.90;\n\n    vector<char> bestActive = st.active;\n    vector<int> bestOwner = st.owner;\n    long long bestCost = st.totalCost;\n\n    // SA schedule (similar to the good 79.24M version)\n    const double T0 = 2e9;\n    const double T1 = 2e6;\n\n    while (elapsed() < TL) {\n        double t = elapsed() / TL;\n        double temp = T0 * pow(T1 / T0, t);\n\n        SAState::Log log(N);\n        log.oldRadio = st.radioCost;\n        log.oldEdge  = st.edgeCost;\n        log.oldTotal = st.totalCost;\n\n        double r = rng.nextDouble();\n        bool ok = false;\n\n        if (r < 0.45) { // remove\n            int v = -1;\n            for (int tries = 0; tries < 20; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (st.active[cand] && !st.ms[cand].empty()) { v = cand; break; }\n            }\n            if (v != -1) ok = st.apply_remove(v, log);\n        } else if (r < 0.80) { // add\n            int u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int cand = rng.nextInt(1, N-1);\n                if (!st.active[cand]) { u = cand; break; }\n            }\n            if (u != -1) ok = st.apply_add(u, log);\n        } else { // swap\n            int v = -1, u = -1;\n            for (int tries = 0; tries < 30; tries++) {\n                int candV = rng.nextInt(1, N-1);\n                if (st.active[candV] && !st.ms[candV].empty()) { v = candV; break; }\n            }\n            for (int tries = 0; tries < 30; tries++) {\n                int candU = rng.nextInt(1, N-1);\n                if (!st.active[candU]) { u = candU; break; }\n            }\n            if (v != -1 && u != -1) ok = st.apply_swap(v, u, log);\n        }\n\n        if (!ok) { st.undo(log); continue; }\n\n        st.finalize(log);\n\n        long long delta = st.totalCost - log.oldTotal;\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else {\n            double prob = exp(-(double)delta / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (!accept) { st.undo(log); continue; }\n\n        if (st.totalCost < bestCost) {\n            bestCost = st.totalCost;\n            bestActive = st.active;\n            bestOwner = st.owner;\n        }\n    }\n\n    // Restore best snapshot\n    st.rebuild_from_active_owner(bestActive, bestOwner);\n\n    // Small post-processing: try to relocate outlier residents greedily\n    // (short time slice)\n    const double POST_TL = 1.97;\n    while (elapsed() < POST_TL) {\n        int s = rng.nextInt(0, N-1);\n        if (s != 0 && st.ms[s].empty()) continue;\n        // pick farthest resident in station s\n        int bestK = -1;\n        int bestD = -1;\n        for (int k = st.head[s]; k != -1; k = st.rnext[k]) {\n            if (st.dOwn[k] > bestD) { bestD = st.dOwn[k]; bestK = k; }\n        }\n        if (bestK == -1) continue;\n\n        // try a few nearest stations as new owner (including currently inactive)\n        int curOwner = st.owner[bestK];\n        long long base = st.totalCost;\n        int bestT = -1;\n\n        for (int idx = 0; idx < 8; idx++) {\n            int tStation = order[bestK][idx];\n            if (tStation == curOwner) continue;\n            int dd = dist2[bestK*N + tStation];\n            if (dd > SAState::D2_LIMIT) continue;\n\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n\n            if (!st.active[tStation]) { log.flipped.push_back({tStation, st.active[tStation]}); st.active[tStation] = 1; }\n            st.move_resident(bestK, tStation, log);\n            st.finalize(log);\n\n            if (st.totalCost < base) {\n                base = st.totalCost;\n                bestT = tStation;\n            }\n            st.undo(log);\n        }\n\n        if (bestT != -1) {\n            SAState::Log log(N);\n            log.oldRadio = st.radioCost;\n            log.oldEdge  = st.edgeCost;\n            log.oldTotal = st.totalCost;\n            if (!st.active[bestT]) { log.flipped.push_back({bestT, st.active[bestT]}); st.active[bestT] = 1; }\n            st.move_resident(bestK, bestT, log);\n            st.finalize(log);\n            // keep only if improved\n            if (st.totalCost >= log.oldTotal) st.undo(log);\n        }\n    }\n\n    // Final cable set (best of two constructions, done only once)\n    vector<int> terms = st.terminals();\n    vector<char> on = conn.steiner_build_best(terms);\n\n    // Output P_1..P_N\n    for (int i = 0; i < N; i++) {\n        int pi = st.P[i];\n        if (pi < 0) pi = 0;\n        if (pi > 5000) pi = 5000;\n        cout << pi << (i+1==N?'\\n':' ');\n    }\n    // Output B_1..B_M\n    for (int j = 0; j < M; j++) {\n        cout << (int)on[j] << (j+1==M?'\\n':' ');\n    }\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int M = N * (N + 1) / 2;\nstatic constexpr int LIMIT = 10000;\n\nstatic inline int ID(int x, int y) { return x * (x + 1) / 2 + y; }\n\n// -------- splitmix64 RNG --------\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n};\n\n// -------- Precompute structure --------\nstruct Precomp {\n    array<int, M> X{}, Y{};\n    array<array<int,2>, M> par{};\n    array<int, M> parCnt{};\n    array<array<int,2>, M> ch{};\n    array<int, M> chCnt{};\n\n    int Ecnt = 0; // downward edges count = N*(N-1)=870\n    array<int, N*(N-1)> eP{};\n    array<int, N*(N-1)> eC{};\n\n    // incident edge ids per node (<=4)\n    array<array<int,4>, M> inc{};\n    array<int, M> incCnt{};\n\n    Precomp() {\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int v = ID(x,y);\n                X[v] = x; Y[v] = y;\n\n                parCnt[v] = 0;\n                if (x > 0) {\n                    if (y > 0) par[v][parCnt[v]++] = ID(x-1, y-1);\n                    if (y < x) par[v][parCnt[v]++] = ID(x-1, y);\n                }\n\n                chCnt[v] = 0;\n                if (x + 1 < N) {\n                    ch[v][chCnt[v]++] = ID(x+1, y);\n                    ch[v][chCnt[v]++] = ID(x+1, y+1);\n                }\n\n                incCnt[v] = 0;\n            }\n        }\n\n        for (int x = 0; x + 1 < N; x++) {\n            for (int y = 0; y <= x; y++) {\n                int p = ID(x,y);\n                for (int i = 0; i < chCnt[p]; i++) {\n                    int c = ch[p][i];\n                    int eid = Ecnt++;\n                    eP[eid] = p;\n                    eC[eid] = c;\n                    inc[p][incCnt[p]++] = eid;\n                    inc[c][incCnt[c]++] = eid;\n                }\n            }\n        }\n    }\n};\nstatic Precomp PC;\n\n// -------- Parameters --------\nstruct Params {\n    // 0: key = diff\n    // 1: key = diff*64 + (N-1-x_parent)\n    int priorityMode = 0;\n\n    // bubble-up when both parents violate:\n    // 0: choose larger parent value\n    // 1: choose smaller parent value\n    int bubbleUpMode = 0;\n\n    bool bubbleDown = true;\n    int bubbleDownLimit = -1; // -1 unlimited\n\n    bool randomized = true;\n\n    int lookahead = 16;     // take top-L violated edges by key\n    int deltaWeight = 5;    // score += deltaWeight * deltaE\n    int posPenalty = 1000;  // if deltaE>0 add posPenalty*deltaE\n};\n\nstruct Result {\n    int E = INT_MAX;\n    int K = INT_MAX;\n    vector<pair<int,int>> ops; // node ids\n};\n\nstatic inline bool better(const Result& A, const Result& B) {\n    if (A.E != B.E) return A.E < B.E;\n    return A.K < B.K;\n}\n\nstruct EdgeCand {\n    int key;\n    int p, c;\n};\n\n// -------- Runner (one attempt) --------\nstruct Runner {\n    array<int, M> a{};\n    int curE = 0;\n    vector<pair<int,int>> ops;\n\n    SplitMix64 rng;\n    Params P;\n    int capK = LIMIT;\n\n    Runner(uint64_t seed, Params params) : rng(seed), P(params) {}\n\n    inline bool violated_eid(int eid) const {\n        return a[PC.eP[eid]] > a[PC.eC[eid]];\n    }\n\n    inline int edge_key(int p, int c) const {\n        int diff = a[p] - a[c];\n        if (P.priorityMode == 0) return diff;\n        int bonus = (N - 1 - PC.X[p]);\n        return diff * 64 + bonus;\n    }\n\n    void init_state(const array<int,M>& initA) {\n        a = initA;\n        ops.clear();\n        curE = 0;\n        for (int eid = 0; eid < PC.Ecnt; eid++) {\n            if (violated_eid(eid)) curE++;\n        }\n    }\n\n    // deltaE if swap u,v (incident edges only), no modification\n    int eval_deltaE(int u, int v) const {\n        int touched[8], tcnt = 0;\n        auto add_eid = [&](int eid) {\n            for (int i = 0; i < tcnt; i++) if (touched[i] == eid) return;\n            touched[tcnt++] = eid;\n        };\n        for (int i = 0; i < PC.incCnt[u]; i++) add_eid(PC.inc[u][i]);\n        for (int i = 0; i < PC.incCnt[v]; i++) add_eid(PC.inc[v][i]);\n\n        int before = 0, after = 0;\n        int au = a[u], av = a[v];\n\n        for (int i = 0; i < tcnt; i++) {\n            int eid = touched[i];\n            int p = PC.eP[eid], c = PC.eC[eid];\n            int ap = a[p], ac = a[c];\n            if (ap > ac) before++;\n\n            if (p == u) ap = av;\n            else if (p == v) ap = au;\n            if (c == u) ac = av;\n            else if (c == v) ac = au;\n\n            if (ap > ac) after++;\n        }\n        return after - before;\n    }\n\n    int estimate_up_steps(int u, int v) const {\n        int steps = 0;\n        while (steps < 40) {\n            int cc = 0, cand[2];\n            for (int i = 0; i < PC.parCnt[u]; i++) {\n                int p = PC.par[u][i];\n                if (a[p] > v) cand[cc++] = p;\n            }\n            if (cc == 0) break;\n            int chosen = cand[0];\n            if (cc == 2) {\n                if (P.bubbleUpMode == 0) {\n                    if (a[cand[1]] > a[chosen]) chosen = cand[1];\n                } else {\n                    if (a[cand[1]] < a[chosen]) chosen = cand[1];\n                }\n            }\n            u = chosen;\n            steps++;\n        }\n        return steps;\n    }\n\n    int estimate_down_steps(int u, int v) const {\n        if (!P.bubbleDown) return 0;\n        int steps = 0;\n        while (steps < 60) {\n            if (P.bubbleDownLimit != -1 && steps >= P.bubbleDownLimit) break;\n            int best = -1;\n            for (int i = 0; i < PC.chCnt[u]; i++) {\n                int c = PC.ch[u][i];\n                if (v > a[c]) {\n                    if (best == -1 || a[c] < a[best]) best = c;\n                }\n            }\n            if (best == -1) break;\n            u = best;\n            steps++;\n        }\n        return steps;\n    }\n\n    bool do_swap_nodes(int u, int v) {\n        // cancel immediate inverse\n        bool can_cancel = !ops.empty() &&\n            ((ops.back().first == u && ops.back().second == v) ||\n             (ops.back().first == v && ops.back().second == u));\n\n        if (!can_cancel) {\n            if ((int)ops.size() >= capK) return false;\n            if ((int)ops.size() >= LIMIT) return false;\n        }\n\n        int touched[8], tcnt = 0;\n        auto add_eid = [&](int eid) {\n            for (int i = 0; i < tcnt; i++) if (touched[i] == eid) return;\n            touched[tcnt++] = eid;\n        };\n        for (int i = 0; i < PC.incCnt[u]; i++) add_eid(PC.inc[u][i]);\n        for (int i = 0; i < PC.incCnt[v]; i++) add_eid(PC.inc[v][i]);\n\n        for (int i = 0; i < tcnt; i++) if (violated_eid(touched[i])) curE--;\n        swap(a[u], a[v]);\n        for (int i = 0; i < tcnt; i++) if (violated_eid(touched[i])) curE++;\n\n        if (can_cancel) ops.pop_back();\n        else ops.push_back({u,v});\n        return true;\n    }\n\n    void bubble_up(int u) {\n        while (true) {\n            int cc = 0, cand[2];\n            for (int i = 0; i < PC.parCnt[u]; i++) {\n                int p = PC.par[u][i];\n                if (a[p] > a[u]) cand[cc++] = p;\n            }\n            if (cc == 0) break;\n\n            int chosen = cand[0];\n            if (cc == 2) {\n                if (P.bubbleUpMode == 0) {\n                    if (a[cand[1]] > a[chosen]) chosen = cand[1];\n                } else {\n                    if (a[cand[1]] < a[chosen]) chosen = cand[1];\n                }\n                if (P.randomized && a[cand[0]] == a[cand[1]]) {\n                    if (rng.next_u32() & 1u) chosen = cand[1];\n                }\n            }\n\n            if (!do_swap_nodes(chosen, u)) break;\n            u = chosen;\n        }\n    }\n\n    void bubble_down(int u) {\n        if (!P.bubbleDown) return;\n        int steps = 0;\n        while (true) {\n            if (P.bubbleDownLimit != -1 && steps >= P.bubbleDownLimit) break;\n\n            int best = -1;\n            for (int i = 0; i < PC.chCnt[u]; i++) {\n                int c = PC.ch[u][i];\n                if (a[u] > a[c]) {\n                    if (best == -1 || a[c] < a[best]) best = c;\n                }\n            }\n            if (best == -1) break;\n\n            if (!do_swap_nodes(u, best)) break;\n            u = best;\n            steps++;\n        }\n    }\n\n    // global rescan: get top-L violated edges by current key\n    bool choose_and_apply_one() {\n        if (curE == 0) return false;\n\n        vector<EdgeCand> cand;\n        cand.reserve(PC.Ecnt);\n\n        for (int eid = 0; eid < PC.Ecnt; eid++) {\n            int p = PC.eP[eid], c = PC.eC[eid];\n            if (a[p] > a[c]) {\n                int key = edge_key(p, c);\n                if (P.randomized) key = (key << 10) + (int)(rng.next_u32() & 1023u);\n                else key = (key << 10);\n                cand.push_back({key, p, c});\n            }\n        }\n        if (cand.empty()) return false; // should match curE==0, but safe\n\n        int L = P.lookahead;\n        if ((int)cand.size() > L) {\n            nth_element(cand.begin(), cand.begin() + L, cand.end(),\n                        [](const EdgeCand& a, const EdgeCand& b){ return a.key > b.key; });\n            cand.resize(L);\n        }\n\n        long long bestScore = (1LL<<62);\n        int bestKey = -1;\n        int bestIdx = 0;\n\n        for (int i = 0; i < (int)cand.size(); i++) {\n            int p = cand[i].p, c = cand[i].c;\n            if (!(a[p] > a[c])) continue; // paranoia\n\n            int dE = eval_deltaE(p, c);\n            int est = 1 + estimate_up_steps(p, a[c]) + estimate_down_steps(c, a[p]);\n\n            long long score = (long long)est + 1LL * P.deltaWeight * dE;\n            if (dE > 0) score += 1LL * P.posPenalty * dE;\n\n            if (score < bestScore || (score == bestScore && cand[i].key > bestKey)) {\n                bestScore = score;\n                bestKey = cand[i].key;\n                bestIdx = i;\n            }\n        }\n\n        int p = cand[bestIdx].p, c = cand[bestIdx].c;\n        if (!(a[p] > a[c])) return true; // stale due to tie randomness; ignore\n        if (!do_swap_nodes(p, c)) return false;\n        bubble_up(p);\n        bubble_down(c);\n        return true;\n    }\n\n    Result run(const array<int,M>& initA) {\n        init_state(initA);\n        while (curE > 0) {\n            if ((int)ops.size() >= capK || (int)ops.size() >= LIMIT) break;\n            if (!choose_and_apply_one()) break;\n        }\n        return Result{curE, (int)ops.size(), ops};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    array<int, M> initA{};\n    uint64_t h = 1469598103934665603ULL;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            int v; cin >> v;\n            initA[ID(x,y)] = v;\n            h ^= (uint64_t)(v + 1);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n    const double TL = 1.90;\n\n    Result best;\n\n    auto attempt = [&](uint64_t seed, const Params& P, int pruneMargin) {\n        Runner r(seed, P);\n        if (best.E == 0) r.capK = min(LIMIT, best.K + pruneMargin);\n        else r.capK = LIMIT;\n        Result res = r.run(initA);\n        if (better(res, best)) best = std::move(res);\n    };\n\n    // Deterministic anchor (no randomness)\n    {\n        Params P;\n        P.priorityMode = 1;\n        P.randomized = false;\n        P.lookahead = 16;\n        P.deltaWeight = 5;\n        P.posPenalty = 1000;\n        attempt(h ^ 0x123456789ABCDEF0ULL, P, 0);\n    }\n\n    // Focused multi-start on a few strong variants\n    vector<Params> vars;\n    {\n        Params P;\n        P.priorityMode = 0;\n        P.randomized = true;\n        P.lookahead = 16;\n        P.deltaWeight = 5;\n        P.posPenalty = 1000;\n        vars.push_back(P);\n\n        P.priorityMode = 1;\n        vars.push_back(P);\n\n        P.bubbleDownLimit = 2; // sometimes reduces K\n        P.priorityMode = 0;\n        vars.push_back(P);\n\n        P.bubbleUpMode = 1; // alternate bubble-up\n        P.bubbleDownLimit = -1;\n        P.priorityMode = 1;\n        vars.push_back(P);\n    }\n\n    int it = 0;\n    while (elapsed() < TL) {\n        uint64_t seed = h + 0x9e3779b97f4a7c15ULL * (uint64_t)(it + 1);\n        const Params& P = vars[it % (int)vars.size()];\n        attempt(seed, P, /*pruneMargin=*/6);\n        it++;\n    }\n\n    cout << best.ops.size() << \"\\n\";\n    for (auto [u,v] : best.ops) {\n        cout << PC.X[u] << \" \" << PC.Y[u] << \" \"\n             << PC.X[v] << \" \" << PC.Y[v] << \"\\n\";\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick(int n=0): n(n), bit(n+1,0) {}\n    void add(int i, int v){\n        for(i++; i<=n; i+=i&-i) bit[i]+=v;\n    }\n    int sumPrefix(int i){ // [0,i)\n        int s=0;\n        for(; i>0; i-=i&-i) s+=bit[i];\n        return s;\n    }\n};\n\nstruct Weights {\n    long long wLab, wM1, wM2, wReach;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed=88172645463325252ull): x(seed?seed:88172645463325252ull) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    // [0,1)\n    double next_double() {\n        // 53-bit mantissa\n        return (next() >> 11) * (1.0 / (double)(1ull << 53));\n    }\n    int next_int(int mod) {\n        return (int)(next() % (uint64_t)mod);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    cin >> D >> N;\n\n    const int ei = 0, ej = (D - 1) / 2;\n    auto inside = [&](int i, int j) { return 0 <= i && i < D && 0 <= j && j < D; };\n    auto vid = [&](int i, int j) { return i * D + j; };\n    auto pos = [&](int v) { return pair<int,int>(v / D, v % D); };\n\n    const int V = D * D;\n    const int root = vid(ei, ej);\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    uint64_t seed_hash = 1469598103934665603ull;\n    auto hash_mix = [&](uint64_t a){\n        seed_hash ^= a + 0x9e3779b97f4a7c15ull + (seed_hash<<6) + (seed_hash>>2);\n    };\n\n    for (int k = 0; k < N; k++) {\n        int r, c; cin >> r >> c;\n        obstacle[r][c] = 1;\n        hash_mix((uint64_t)r * 1315423911ull + (uint64_t)c * 2654435761ull + 7);\n    }\n\n    // neighbors\n    vector<array<int,4>> nbr(V);\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = pos(v);\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d], nj = j + dj[d];\n            nbr[v][d] = inside(ni, nj) ? vid(ni, nj) : -1;\n        }\n    }\n\n    // storable cells\n    vector<int> storableCells;\n    storableCells.reserve(V);\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == ei && j == ej) continue;\n        if (obstacle[i][j]) continue;\n        storableCells.push_back(vid(i, j));\n    }\n    const int M = (int)storableCells.size(); // <= 80\n\n    // cell -> container index k\n    vector<int> kOfCell(V, -1);\n    for (int k = 0; k < M; k++) kOfCell[storableCells[k]] = k;\n\n    // dist ignoring containers\n    const int INF = 1e9;\n    vector<int> dist(V, INF);\n    {\n        queue<int> q;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            auto [i, j] = pos(v);\n            if (obstacle[i][j]) continue;\n            for (int d = 0; d < 4; d++) {\n                int u = nbr[v][d];\n                if (u < 0) continue;\n                auto [ui, uj] = pos(u);\n                if (obstacle[ui][uj]) continue;\n                if (dist[u] > dist[v] + 1) {\n                    dist[u] = dist[v] + 1;\n                    q.push(u);\n                }\n            }\n        }\n    }\n\n    // degree\n    vector<int> deg(V, 0);\n    for (int v = 0; v < V; v++) {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) continue;\n        int c = 0;\n        for (int d = 0; d < 4; d++) {\n            int u = nbr[v][d];\n            if (u < 0) continue;\n            auto [ui, uj] = pos(u);\n            if (obstacle[ui][uj]) continue;\n            c++;\n        }\n        deg[v] = c;\n    }\n\n    // placement priority\n    vector<int> priority = storableCells;\n    sort(priority.begin(), priority.end(), [&](int a, int b) {\n        if (dist[a] != dist[b]) return dist[a] < dist[b];\n        if (deg[a] != deg[b]) return deg[a] > deg[b];\n        return a < b;\n    });\n    vector<int> rankv(V, -1);\n    for (int r = 0; r < M; r++) rankv[priority[r]] = r;\n\n    // placement state\n    vector<char> occupied(V, 0);\n    vector<int> label_at(V, -1);\n\n    auto is_empty_placement = [&](int v) -> bool {\n        auto [i, j] = pos(v);\n        if (obstacle[i][j]) return false;\n        if (v == root) return true;\n        return !occupied[v];\n    };\n\n    auto bfs_reachable_empty_placement = [&](vector<char>& vis) -> int {\n        vis.assign(V, 0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n        int cnt = 1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (int d = 0; d < 4; d++) {\n                int u = nbr[v][d];\n                if (u < 0) continue;\n                if (vis[u]) continue;\n                if (!is_empty_placement(u)) continue;\n                vis[u] = 1;\n                q.push(u);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    auto count_total_empty_placement = [&]() -> int {\n        int total = 0;\n        for (int v = 0; v < V; v++) {\n            auto [i, j] = pos(v);\n            if (obstacle[i][j]) continue;\n            if (v == root) { total++; continue; }\n            if (!occupied[v]) total++;\n        }\n        return total;\n    };\n\n    auto placement_is_safe = [&](int cell) -> bool {\n        occupied[cell] = 1;\n        vector<char> vis;\n        int reach = bfs_reachable_empty_placement(vis);\n        int total = count_total_empty_placement();\n        occupied[cell] = 0;\n        return reach == total;\n    };\n\n    // ===== Placement (interactive) =====\n    for (int step = 0; step < M; step++) {\n        int t; cin >> t;\n        hash_mix((uint64_t)t * 1000003ull + (uint64_t)step * 911382323ull);\n\n        vector<char> vis;\n        bfs_reachable_empty_placement(vis);\n\n        struct Cand { int v; long long key; };\n        vector<Cand> order;\n        order.reserve(M);\n\n        for (int v : storableCells) {\n            if (occupied[v]) continue;\n            if (!vis[v]) continue;\n            long long diff = (long long)rankv[v] - t;\n            long long key = diff * diff * 1000LL + dist[v] * 10LL - deg[v];\n            order.push_back({v, key});\n        }\n        sort(order.begin(), order.end(), [&](const Cand& a, const Cand& b) {\n            if (a.key != b.key) return a.key < b.key;\n            return a.v < b.v;\n        });\n\n        int chosen = -1;\n        int L = min<int>(12, (int)order.size());\n        for (int i = 0; i < L; i++) {\n            int v = order[i].v;\n            if (placement_is_safe(v)) { chosen = v; break; }\n        }\n        if (chosen == -1) {\n            for (auto &c : order) if (placement_is_safe(c.v)) { chosen = c.v; break; }\n        }\n        if (chosen == -1) chosen = order[0].v; // should not happen\n\n        occupied[chosen] = 1;\n        label_at[chosen] = t;\n\n        auto [pi, pj] = pos(chosen);\n        cout << pi << ' ' << pj << '\\n';\n        cout.flush();\n    }\n\n    // ===== Shipping prep =====\n    vector<int> labelOf(M);\n    for (int k = 0; k < M; k++) labelOf[k] = label_at[storableCells[k]];\n\n    // BFS-based boundary (proven safe)\n    auto isEmptyShipCell = [&](int cell, const vector<char>& removedK) -> bool {\n        auto [i, j] = pos(cell);\n        if (obstacle[i][j]) return false;\n        if (cell == root) return true;\n        int k = kOfCell[cell];\n        if (k < 0) return false;\n        return removedK[k];\n    };\n\n    auto compute_boundary = [&](const vector<char>& removedK, vector<int>& boundaryK, int& reachEmpty) {\n        static array<char, 81> vis;\n        vis.fill(0);\n        array<int, 81> q;\n        int qh = 0, qt = 0;\n\n        vis[root] = 1;\n        q[qt++] = root;\n\n        while (qh < qt) {\n            int v = q[qh++];\n            for (int d = 0; d < 4; d++) {\n                int u = nbr[v][d];\n                if (u < 0) continue;\n                if (vis[u]) continue;\n                if (!isEmptyShipCell(u, removedK)) continue;\n                vis[u] = 1;\n                q[qt++] = u;\n            }\n        }\n        reachEmpty = qt;\n\n        static array<char, 80> seenK;\n        for (int i = 0; i < M; i++) seenK[i] = 0;\n        boundaryK.clear();\n        boundaryK.reserve(40);\n\n        for (int qi = 0; qi < qt; qi++) {\n            int v = q[qi];\n            for (int d = 0; d < 4; d++) {\n                int u = nbr[v][d];\n                if (u < 0) continue;\n                int k = kOfCell[u];\n                if (k < 0) continue;\n                if (removedK[k]) continue;\n                if (!seenK[k]) {\n                    seenK[k] = 1;\n                    boundaryK.push_back(k);\n                }\n            }\n        }\n    };\n\n    auto inversionCountSeqK = [&](const vector<int>& seqK) -> long long {\n        Fenwick fw(M);\n        long long inv = 0;\n        for (int i = 0; i < M; i++) {\n            int lab = labelOf[seqK[i]];\n            inv += i - fw.sumPrefix(lab + 1);\n            fw.add(lab, 1);\n        }\n        return inv;\n    };\n\n    // Repair to guarantee legality (even if proposal is weird)\n    auto repair_sequence = [&](const vector<int>& proposal) -> vector<int> {\n        vector<int> seq;\n        seq.reserve(M);\n        vector<char> removed(M, 0);\n        vector<int> boundary;\n        int p = 0;\n\n        for (int step = 0; step < M; step++) {\n            int reach = 0;\n            compute_boundary(removed, boundary, reach);\n            if (boundary.empty()) {\n                for (int k = 0; k < M; k++) if (!removed[k]) { boundary.push_back(k); break; }\n            }\n\n            auto inBoundary = [&](int k) -> bool {\n                for (int x : boundary) if (x == k) return true;\n                return false;\n            };\n\n            int chosen = -1;\n            while (p < (int)proposal.size()) {\n                int k = proposal[p++];\n                if (0 <= k && k < M && !removed[k] && inBoundary(k)) {\n                    chosen = k;\n                    break;\n                }\n            }\n            if (chosen == -1) {\n                // fallback: smallest label, tie by dist/deg\n                chosen = boundary[0];\n                for (int k : boundary) {\n                    if (labelOf[k] != labelOf[chosen]) {\n                        if (labelOf[k] < labelOf[chosen]) chosen = k;\n                    } else {\n                        int ck = storableCells[k], cc = storableCells[chosen];\n                        if (dist[ck] != dist[cc]) {\n                            if (dist[ck] < dist[cc]) chosen = k;\n                        } else if (deg[ck] != deg[cc]) {\n                            if (deg[ck] > deg[cc]) chosen = k;\n                        }\n                    }\n                }\n            }\n\n            removed[chosen] = 1;\n            seq.push_back(chosen);\n        }\n        return seq;\n    };\n\n    // 1-step lookahead plan; optional stochastic pick among top few\n    auto plan_lookahead = [&](Weights W, XorShift64* rng, double temperature, bool stochastic) -> vector<int> {\n        vector<int> seq;\n        seq.reserve(M);\n        vector<char> removed(M, 0);\n        vector<int> boundary, boundary2;\n\n        for (int step = 0; step < M; step++) {\n            int reach = 0;\n            compute_boundary(removed, boundary, reach);\n            if (boundary.empty()) break;\n\n            // candidates = small labels + \"unlocky\"\n            vector<int> byLabel = boundary;\n            sort(byLabel.begin(), byLabel.end(), [&](int a, int b){\n                if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n                return a < b;\n            });\n            if ((int)byLabel.size() > 15) byLabel.resize(15);\n\n            vector<int> byUnlock = boundary;\n            sort(byUnlock.begin(), byUnlock.end(), [&](int a, int b){\n                int ca = storableCells[a], cb = storableCells[b];\n                if (dist[ca] != dist[cb]) return dist[ca] < dist[cb];\n                if (deg[ca] != deg[cb]) return deg[ca] > deg[cb];\n                if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n                return a < b;\n            });\n            if ((int)byUnlock.size() > 8) byUnlock.resize(8);\n\n            vector<int> cand = byLabel;\n            cand.insert(cand.end(), byUnlock.begin(), byUnlock.end());\n            sort(cand.begin(), cand.end());\n            cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n            struct Sc { long long s; int k; };\n            vector<Sc> scored;\n            scored.reserve(cand.size());\n\n            for (int k : cand) {\n                removed[k] = 1;\n                int reach2 = 0;\n                compute_boundary(removed, boundary2, reach2);\n\n                int m1 = M + 5, m2 = M + 5;\n                for (int kk : boundary2) {\n                    int lab = labelOf[kk];\n                    if (lab < m1) { m2 = m1; m1 = lab; }\n                    else if (lab < m2) { m2 = lab; }\n                }\n\n                long long score = W.wLab * (long long)labelOf[k]\n                                + W.wM1  * (long long)m1\n                                + W.wM2  * (long long)m2\n                                - W.wReach * (long long)reach2;\n                score = score * 10 + dist[storableCells[k]]; // tie-break\n\n                removed[k] = 0;\n                scored.push_back({score, k});\n            }\n\n            sort(scored.begin(), scored.end(), [&](const Sc& a, const Sc& b){\n                if (a.s != b.s) return a.s < b.s;\n                return a.k < b.k;\n            });\n\n            int chosen = scored[0].k;\n\n            if (stochastic && rng && scored.size() >= 2) {\n                int T = min<int>(3, (int)scored.size());\n                long long best = scored[0].s;\n                // softmax over top T\n                double sumw = 0.0;\n                array<double, 3> w{};\n                for (int i = 0; i < T; i++) {\n                    double x = (double)(scored[i].s - best);\n                    double wi = exp(-x / max(1e-9, temperature));\n                    w[i] = wi;\n                    sumw += wi;\n                }\n                double r = rng->next_double() * sumw;\n                int pick = 0;\n                for (int i = 0; i < T; i++) {\n                    r -= w[i];\n                    if (r <= 0) { pick = i; break; }\n                }\n                chosen = scored[pick].k;\n            }\n\n            removed[chosen] = 1;\n            seq.push_back(chosen);\n        }\n        return seq;\n    };\n\n    // 2-step lookahead variant (still cheap); used for a couple candidates only\n    auto plan_2step = [&](Weights W) -> vector<int> {\n        vector<int> seq;\n        seq.reserve(M);\n        vector<char> removed(M, 0);\n        vector<int> boundary, boundary1, boundary2;\n\n        for (int step = 0; step < M; step++) {\n            int reach0 = 0;\n            compute_boundary(removed, boundary, reach0);\n            if (boundary.empty()) break;\n\n            vector<int> byLabel = boundary;\n            sort(byLabel.begin(), byLabel.end(), [&](int a, int b){\n                if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n                return a < b;\n            });\n            if ((int)byLabel.size() > 10) byLabel.resize(10);\n\n            // only do 2-step when boundary is small-ish or early\n            bool do2 = ((int)boundary.size() <= 10) || (step < 20);\n\n            int bestK = byLabel[0];\n            long long bestScore = (1LL<<62);\n\n            for (int k1 : byLabel) {\n                // evaluate first move by looking at the best second move among top few\n                removed[k1] = 1;\n\n                int reach1 = 0;\n                compute_boundary(removed, boundary1, reach1);\n\n                // compute immediate score component like 1-step lookahead would\n                int m1 = M + 5, m2 = M + 5;\n                for (int kk : boundary1) {\n                    int lab = labelOf[kk];\n                    if (lab < m1) { m2 = m1; m1 = lab; }\n                    else if (lab < m2) { m2 = lab; }\n                }\n                long long s1 = W.wLab * (long long)labelOf[k1]\n                             + W.wM1  * (long long)m1\n                             + W.wM2  * (long long)m2\n                             - W.wReach * (long long)reach1;\n                s1 = s1 * 10 + dist[storableCells[k1]];\n\n                long long sTot = s1;\n\n                if (do2 && !boundary1.empty()) {\n                    vector<int> byLabel2 = boundary1;\n                    sort(byLabel2.begin(), byLabel2.end(), [&](int a, int b){\n                        if (labelOf[a] != labelOf[b]) return labelOf[a] < labelOf[b];\n                        return a < b;\n                    });\n                    if ((int)byLabel2.size() > 8) byLabel2.resize(8);\n\n                    long long bestS2 = (1LL<<62);\n                    for (int k2 : byLabel2) {\n                        removed[k2] = 1;\n                        int reach2 = 0;\n                        compute_boundary(removed, boundary2, reach2);\n\n                        int mm1 = M + 5, mm2 = M + 5;\n                        for (int kk : boundary2) {\n                            int lab = labelOf[kk];\n                            if (lab < mm1) { mm2 = mm1; mm1 = lab; }\n                            else if (lab < mm2) { mm2 = lab; }\n                        }\n\n                        long long s2 = W.wLab * (long long)labelOf[k2]\n                                     + W.wM1  * (long long)mm1\n                                     + W.wM2  * (long long)mm2\n                                     - W.wReach * (long long)reach2;\n                        s2 = s2 * 10 + dist[storableCells[k2]];\n                        bestS2 = min(bestS2, s2);\n\n                        removed[k2] = 0;\n                    }\n                    if (bestS2 < (1LL<<61)) sTot += bestS2 / 20; // discounted 2nd-step signal\n                }\n\n                removed[k1] = 0;\n\n                if (sTot < bestScore) {\n                    bestScore = sTot;\n                    bestK = k1;\n                }\n            }\n\n            removed[bestK] = 1;\n            seq.push_back(bestK);\n        }\n        return seq;\n    };\n\n    // Baseline min-label\n    auto plan_minlabel = [&]() -> vector<int> {\n        vector<int> seq;\n        seq.reserve(M);\n        vector<char> removed(M, 0);\n        vector<int> boundary;\n        for (int step = 0; step < M; step++) {\n            int reach = 0;\n            compute_boundary(removed, boundary, reach);\n            if (boundary.empty()) break;\n            int bestK = boundary[0];\n            for (int k : boundary) if (labelOf[k] < labelOf[bestK]) bestK = k;\n            removed[bestK] = 1;\n            seq.push_back(bestK);\n        }\n        return seq;\n    };\n\n    // ===== Generate shipping candidates (low-risk) and select best by exact inversions =====\n    XorShift64 rng(seed_hash);\n\n    vector<vector<int>> candidates;\n    candidates.reserve(64);\n\n    // Always include the known strong baseline\n    Weights baseW{1000000, 5000, 500, 5};\n    candidates.push_back(plan_lookahead(baseW, nullptr, 1.0, false));\n    candidates.push_back(plan_2step(baseW));\n    candidates.push_back(plan_minlabel());\n\n    // Small deterministic ensemble around baseline\n    vector<Weights> Ws = {\n        {1200000, 4500, 450, 5},\n        { 900000, 6500, 700, 6},\n        {1300000, 5000, 500, 3},\n        { 850000, 9000, 1200, 10},\n        {1100000, 6000, 700, 7},\n        {1000000, 6500, 800, 8},\n    };\n    for (auto w : Ws) candidates.push_back(plan_lookahead(w, nullptr, 1.0, false));\n\n    // Stochastic restarts (diversify without risking legality)\n    // Slight random weight perturbation + stochastic choice among top-3\n    for (int it = 0; it < 18; it++) {\n        long long dl = (long long)( (int)rng.next_int(300001) - 150000 ); // +/-150k\n        long long dm1 = (long long)( (int)rng.next_int(4001) - 2000 );    // +/-2000\n        long long dm2 = (long long)( (int)rng.next_int(801) - 400 );      // +/-400\n        long long dr  = (long long)( (int)rng.next_int(7) - 3 );          // +/-3\n\n        Weights w{\n            max(200000LL, baseW.wLab + dl),\n            max(0LL, baseW.wM1 + dm1),\n            max(0LL, baseW.wM2 + dm2),\n            max(0LL, baseW.wReach + dr)\n        };\n        double temp = 2000.0 + 2000.0 * rng.next_double(); // 2000..4000\n        candidates.push_back(plan_lookahead(w, &rng, temp, true));\n    }\n\n    long long bestInv = (1LL<<62);\n    vector<int> bestSeq;\n\n    for (auto &cand : candidates) {\n        auto repaired = repair_sequence(cand);\n        if ((int)repaired.size() != M) continue;\n        long long inv = inversionCountSeqK(repaired);\n        if (inv < bestInv) {\n            bestInv = inv;\n            bestSeq = move(repaired);\n        }\n    }\n\n    // Output shipping order\n    for (int k : bestSeq) {\n        int cell = storableCells[k];\n        auto [qi, qj] = pos(cell);\n        cout << qi << ' ' << qj << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int DX[4] = {1, -1, 0, 0};\nstatic constexpr int DY[4] = {0, 0, 1, -1};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\n// splitmix64 for deterministic hashing\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> orig(n, vector<int>(n));\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> orig[i][j];\n\n    const int C = m + 1; // 0..m\n\n    auto inside = [&](int i, int j) { return (0 <= i && i < n && 0 <= j && j < n); };\n    auto is_boundary = [&](int i, int j) { return (i == 0 || i == n - 1 || j == 0 || j == n - 1); };\n    auto idx = [&](int i, int j) { return i * n + j; };\n\n    // Required adjacency existence\n    vector<vector<char>> req(C, vector<char>(C, 0));\n    vector<char> req0(C, 0);\n\n    // Non-zero adjacencies from original\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int a = orig[i][j];\n            if (i + 1 < n) {\n                int b = orig[i + 1][j];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n            if (j + 1 < n) {\n                int b = orig[i][j + 1];\n                if (a != b) req[a][b] = req[b][a] = 1;\n            }\n        }\n    }\n    // Outside adjacency: boundary touches 0\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) if (is_boundary(i, j)) {\n            int c = orig[i][j];\n            req[0][c] = req[c][0] = 1;\n            req0[c] = 1;\n        }\n    }\n\n    auto coastal = [&](int c) -> bool { return c > 0 && req0[c]; };\n\n    // Build adjacency list of colors (1..m), compute dist-to-coast on this graph\n    vector<vector<int>> adj(m + 1);\n    for (int u = 1; u <= m; u++) {\n        for (int v = 1; v <= m; v++) if (req[u][v]) adj[u].push_back(v);\n    }\n\n    const int INF = 1e9;\n    vector<int> dist(C, INF);\n    deque<int> q;\n    for (int c = 1; c <= m; c++) if (coastal(c)) { dist[c] = 0; q.push_back(c); }\n    while (!q.empty()) {\n        int u = q.front(); q.pop_front();\n        for (int v : adj[u]) {\n            if (dist[v] > dist[u] + 1) {\n                dist[v] = dist[u] + 1;\n                q.push_back(v);\n            }\n        }\n    }\n\n    // Deterministic seed from input (avoid catastrophic variance)\n    uint64_t seed = 0;\n    seed ^= splitmix64((uint64_t)n * 1000003ULL + (uint64_t)m);\n    // sample a few cells\n    for (int i : {0, 1, 2, 7, 13, 23, 37, 49}) {\n        for (int j : {0, 3, 5, 11, 19, 29, 41, 49}) {\n            seed ^= splitmix64((uint64_t)(i + 1) * 1315423911ULL ^ (uint64_t)(j + 7) * 2654435761ULL ^ (uint64_t)orig[i][j]);\n        }\n    }\n    std::mt19937 rng((uint32_t)seed);\n\n    // Current grid\n    vector<vector<int>> g = orig;\n\n    // Sizes\n    vector<int> sz(C, 0);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) sz[g[i][j]]++;\n\n    // Edge counts ec[min][max]\n    vector<vector<int>> ec(C, vector<int>(C, 0));\n    auto addEdge = [&](int u, int v, int delta) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        ec[u][v] += delta;\n    };\n    auto getEdge = [&](int u, int v) -> int {\n        if (u == v) return 0;\n        if (u > v) swap(u, v);\n        return ec[u][v];\n    };\n\n    // init edge counts\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n        int a = g[i][j];\n        if (i + 1 < n) addEdge(a, g[i + 1][j], +1);\n        if (j + 1 < n) addEdge(a, g[i][j + 1], +1);\n        if (i == 0) addEdge(0, a, +1);\n        if (i == n - 1) addEdge(0, a, +1);\n        if (j == 0) addEdge(0, a, +1);\n        if (j == n - 1) addEdge(0, a, +1);\n    }\n\n    // Connectivity check for removing one cell of color c\n    vector<int> vis(n * n, 0);\n    int vis_stamp = 1;\n\n    auto connected_after_remove = [&](int i, int j, int c) -> bool {\n        int si = -1, sj = -1;\n        int same_deg = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == c) {\n                same_deg++;\n                if (si == -1) { si = ni; sj = nj; }\n            }\n        }\n        if (si == -1) return false;\n        if (same_deg <= 1) return true; // leaf removal safe\n\n        int target = sz[c] - 1;\n        vis_stamp++;\n        deque<pair<int,int>> qq;\n        qq.push_back({si, sj});\n        vis[idx(si, sj)] = vis_stamp;\n        int cnt = 1;\n        while (!qq.empty()) {\n            auto [x, y] = qq.front(); qq.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!inside(nx, ny)) continue;\n                if (nx == i && ny == j) continue;\n                if (g[nx][ny] != c) continue;\n                int id = idx(nx, ny);\n                if (vis[id] == vis_stamp) continue;\n                vis[id] = vis_stamp;\n                qq.push_back({nx, ny});\n                cnt++;\n            }\n        }\n        return cnt == target;\n    };\n\n    auto adjacent_to_zero_or_outside = [&](int i, int j) -> bool {\n        if (is_boundary(i, j)) return true;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (inside(ni, nj) && g[ni][nj] == 0) return true;\n        }\n        return false;\n    };\n\n    // Necessary local compatibility for recolor to b\n    auto locally_compatible = [&](int i, int j, int b) -> bool {\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d == b) continue;\n            if (!req[b][d]) return false;\n        }\n        return true;\n    };\n\n    // Core legal move: recolor old -> newc (newc can be 0)\n    auto try_apply = [&](int i, int j, int newc) -> bool {\n        int old = g[i][j];\n        if (old == 0 || old == newc) return false;\n        if (sz[old] <= 1) return false;\n\n        if (newc == 0) {\n            if (!adjacent_to_zero_or_outside(i, j)) return false;\n        } else {\n            bool touch = false;\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj) && g[ni][nj] == newc) { touch = true; break; }\n            }\n            if (!touch) return false;\n        }\n\n        if (!connected_after_remove(i, j, old)) return false;\n\n        int keys[16], vals[16], ksz = 0;\n        auto addDelta = [&](int u, int v, int delta) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            int key = u * C + v;\n            for (int t = 0; t < ksz; t++) if (keys[t] == key) { vals[t] += delta; return; }\n            keys[ksz] = key;\n            vals[ksz] = delta;\n            ksz++;\n        };\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addDelta(old, d, -1);\n            if (newc != d) addDelta(newc, d, +1);\n        }\n\n        for (int t = 0; t < ksz; t++) {\n            int key = keys[t];\n            int u = key / C;\n            int v = key % C;\n            int cur = getEdge(u, v);\n            int nxt = cur + vals[t];\n            if (nxt < 0) return false;\n            if (req[u][v]) { if (nxt == 0) return false; }\n            else { if (nxt != 0) return false; }\n        }\n\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (old != d) addEdge(old, d, -1);\n            if (newc != d) addEdge(newc, d, +1);\n        }\n\n        g[i][j] = newc;\n        sz[old]--;\n        if (newc > 0) sz[newc]++;\n\n        return true;\n    };\n\n    // Precheck for deletion c->0: any neighbor d!=c that becomes adjacent to 0 must be coastal\n    auto delete_precheck = [&](int i, int j) -> bool {\n        int c = g[i][j];\n        if (c <= 0 || !coastal(c)) return false;\n        if (!adjacent_to_zero_or_outside(i, j)) return false;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            int d = inside(ni, nj) ? g[ni][nj] : 0;\n            if (d > 0 && d != c && !coastal(d)) return false;\n        }\n        return true;\n    };\n\n    Timer timer;\n    const double TL = 1.90;\n    const double PHASE1 = 1.25; // IMPORTANT: recolor-only phase (stability)\n\n    // Candidate pool with duplicates (high-throughput exploration)\n    vector<int> cand;\n    cand.reserve(n * n * 10);\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cand.push_back(idx(i, j));\n\n    auto push_around = [&](int i, int j) {\n        for (int di = -1; di <= 1; di++) for (int dj = -1; dj <= 1; dj++) {\n            int x = i + di, y = j + dj;\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n        for (int k = 0; k < 4; k++) {\n            int x = i + DX[k], y = j + DY[k];\n            if (inside(x, y)) cand.push_back(idx(x, y));\n        }\n    };\n\n    auto refill = [&]() {\n        // keep pool populated but bounded\n        if ((int)cand.size() < 8000) {\n            for (int t = 0; t < 8000; t++) cand.push_back((int)(rng() % (n * n)));\n        }\n        if ((int)cand.size() > 300000) {\n            // downsample to avoid memory/time blowups\n            vector<int> tmp;\n            tmp.reserve(120000);\n            for (int t = 0; t < 120000; t++) tmp.push_back(cand[rng() % cand.size()]);\n            cand.swap(tmp);\n        }\n    };\n\n    // Main loop\n    while (timer.elapsed() < TL) {\n        refill();\n        int pos = (int)(rng() % cand.size());\n        int id = cand[pos];\n        cand[pos] = cand.back();\n        cand.pop_back();\n\n        int i = id / n, j = id % n;\n        int old = g[i][j];\n        if (old == 0) continue;\n\n        bool allowDelete = (timer.elapsed() >= PHASE1);\n\n        // Phase2: try delete first\n        if (allowDelete && delete_precheck(i, j)) {\n            if (try_apply(i, j, 0)) {\n                push_around(i, j);\n                continue;\n            }\n        }\n\n        // Recolor: choose neighbor with smaller dist (or equal dist rarely)\n        int neigh[4]; int ns = 0;\n        for (int k = 0; k < 4; k++) {\n            int ni = i + DX[k], nj = j + DY[k];\n            if (!inside(ni, nj)) continue;\n            int b = g[ni][nj];\n            if (b > 0 && b != old) neigh[ns++] = b;\n        }\n        if (ns == 0) continue;\n        sort(neigh, neigh + ns);\n        ns = (int)(unique(neigh, neigh + ns) - neigh);\n\n        // Sort by dist then prefer coastal to help later deletions\n        vector<int> opts(neigh, neigh + ns);\n        sort(opts.begin(), opts.end(), [&](int a, int b) {\n            if (dist[a] != dist[b]) return dist[a] < dist[b];\n            return (int)coastal(a) > (int)coastal(b);\n        });\n\n        int dOld = dist[old];\n        for (int b : opts) {\n            int dNew = dist[b];\n            if (dNew > dOld) continue;\n            if (dNew == dOld) {\n                // exploration probability (a bit higher in phase2)\n                int P = allowDelete ? 60 : 180;\n                if ((int)(rng() % P) != 0) continue;\n            }\n            if (!locally_compatible(i, j, b)) continue;\n            if (try_apply(i, j, b)) {\n                push_around(i, j);\n                break;\n            }\n        }\n    }\n\n    // Final greedy deletion flood: seed from boundary AND current 0-frontier\n    deque<int> dq;\n    vector<char> inq(n * n, 0);\n    auto push_del = [&](int x, int y) {\n        if (!inside(x, y)) return;\n        int id = idx(x, y);\n        if (!inq[id]) { inq[id] = 1; dq.push_back(id); }\n    };\n\n    for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n        if (is_boundary(i, j)) push_del(i, j);\n        if (g[i][j] == 0) {\n            for (int k = 0; k < 4; k++) {\n                int ni = i + DX[k], nj = j + DY[k];\n                if (inside(ni, nj)) push_del(ni, nj);\n            }\n        }\n    }\n\n    while (!dq.empty() && timer.elapsed() < TL) {\n        int id = dq.front(); dq.pop_front();\n        inq[id] = 0;\n        int i = id / n, j = id % n;\n        if (!delete_precheck(i, j)) continue;\n        if (try_apply(i, j, 0)) {\n            push_del(i, j);\n            for (int k = 0; k < 4; k++) push_del(i + DX[k], j + DY[k]);\n        }\n    }\n\n    // Safety verify (fallback to orig if anything wrong)\n    auto verify = [&]() -> bool {\n        vector<int> cnt(C, 0);\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cnt[g[i][j]]++;\n        for (int c = 1; c <= m; c++) if (cnt[c] == 0) return false;\n\n        // connectivity for colors 1..m\n        vector<int> v(n * n, 0);\n        int st = 1;\n        for (int c = 1; c <= m; c++) {\n            int si = -1, sj = -1;\n            for (int i = 0; i < n && si == -1; i++)\n                for (int j = 0; j < n; j++)\n                    if (g[i][j] == c) { si = i; sj = j; break; }\n            st++;\n            deque<pair<int,int>> qq;\n            qq.push_back({si, sj});\n            v[idx(si, sj)] = st;\n            int got = 1;\n            while (!qq.empty()) {\n                auto [x, y] = qq.front(); qq.pop_front();\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + DX[k], ny = y + DY[k];\n                    if (!inside(nx, ny)) continue;\n                    if (g[nx][ny] != c) continue;\n                    int id2 = idx(nx, ny);\n                    if (v[id2] == st) continue;\n                    v[id2] = st;\n                    qq.push_back({nx, ny});\n                    got++;\n                }\n            }\n            if (got != cnt[c]) return false;\n        }\n\n        // 0 connected to outside (padded BFS)\n        int N = n + 2;\n        auto at = [&](int x, int y) -> int {\n            if (x == 0 || y == 0 || x == N - 1 || y == N - 1) return 0;\n            return g[x - 1][y - 1];\n        };\n        vector<char> vz(N * N, 0);\n        deque<pair<int,int>> q0;\n        q0.push_back({0, 0});\n        vz[0] = 1;\n        while (!q0.empty()) {\n            auto [x, y] = q0.front(); q0.pop_front();\n            for (int k = 0; k < 4; k++) {\n                int nx = x + DX[k], ny = y + DY[k];\n                if (!(0 <= nx && nx < N && 0 <= ny && ny < N)) continue;\n                int nid = nx * N + ny;\n                if (vz[nid]) continue;\n                if (at(nx, ny) != 0) continue;\n                vz[nid] = 1;\n                q0.push_back({nx, ny});\n            }\n        }\n        for (int x = 1; x <= n; x++)\n            for (int y = 1; y <= n; y++)\n                if (g[x - 1][y - 1] == 0 && !vz[x * N + y]) return false;\n\n        // adjacency graph equals req\n        vector<vector<char>> outAdj(C, vector<char>(C, 0));\n        auto mark = [&](int u, int v) {\n            if (u == v) return;\n            outAdj[u][v] = outAdj[v][u] = 1;\n        };\n        for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {\n            int a = g[i][j];\n            if (i + 1 < n) mark(a, g[i + 1][j]);\n            if (j + 1 < n) mark(a, g[i][j + 1]);\n            if (i == 0) mark(0, a);\n            if (i == n - 1) mark(0, a);\n            if (j == 0) mark(0, a);\n            if (j == n - 1) mark(0, a);\n        }\n        for (int u = 0; u <= m; u++)\n            for (int v = u + 1; v <= m; v++)\n                if (outAdj[u][v] != req[u][v]) return false;\n\n        return true;\n    };\n\n    if (!verify()) g = orig;\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            if (j) cout << ' ';\n            cout << g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift {\n    using ull = unsigned long long;\n    ull x;\n    explicit XorShift(ull seed = 88172645463325252ULL) : x(seed) {}\n    ull nextUll() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int lo, int hi) { // inclusive\n        return lo + (int)(nextUll() % (ull)(hi - lo + 1));\n    }\n};\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n    int cmpLimit = 0; // after this, cmpItem becomes deterministic (no more queries)\n\n    vector<vector<int>> bins;\n    vector<int> ans;\n\n    // itemCmp[a][b] for a<b: 2 unknown, else -1/0/1 meaning wa ? wb\n    vector<vector<int8_t>> itemCmp;\n\n    XorShift rng;\n\n    Solver() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    char querySets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) return '=';\n        cout << (int)L.size() << \" \" << (int)R.size();\n        for (int x : L) cout << \" \" << x;\n        for (int x : R) cout << \" \" << x;\n        cout << \"\\n\";\n        cout.flush();\n        string s;\n        cin >> s;\n        used++;\n        return s[0];\n    }\n\n    int cmpItem(int i, int j) {\n        if (i == j) return 0;\n        // If out of budget for item comparisons, fall back to deterministic ordering.\n        if (used >= Q || used >= cmpLimit) return (i < j ? -1 : +1);\n\n        int a = min(i, j), b = max(i, j);\n        int8_t &v = itemCmp[a][b];\n        if (v != 2) {\n            int res = (int)v;\n            return (i == a ? res : -res);\n        }\n        char r = querySets(vector<int>{i}, vector<int>{j});\n        int res = (r == '<' ? -1 : (r == '>' ? +1 : 0));\n        int store = (i == a ? res : -res);\n        v = (int8_t)store;\n        return res;\n    }\n\n    static int ceil_log2(int n) {\n        int k = 0, p = 1;\n        while (p < n) { p <<= 1; k++; }\n        return k;\n    }\n    static long long clamp_ll(long long x, long long lo, long long hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    // Build max-tournament among items, record beaten lists.\n    int buildTournament(const vector<int>& items, vector<vector<int>>& beaten) {\n        vector<int> cur = items;\n        while ((int)cur.size() > 1 && used < cmpLimit) {\n            vector<int> nxt;\n            nxt.reserve((cur.size() + 1) / 2);\n            for (int i = 0; i < (int)cur.size(); i += 2) {\n                if (i + 1 == (int)cur.size()) {\n                    nxt.push_back(cur[i]);\n                } else {\n                    int a = cur[i], b = cur[i + 1];\n                    int c = cmpItem(a, b);\n                    int win = (c >= 0 ? a : b);\n                    int lose = (c >= 0 ? b : a);\n                    beaten[win].push_back(lose);\n                    nxt.push_back(win);\n                }\n            }\n            cur.swap(nxt);\n        }\n        return cur[0];\n    }\n\n    // Explicit-comparator heap (avoids UB)\n    struct MaxHeap {\n        Solver* s;\n        vector<int> h;\n        explicit MaxHeap(Solver* ss) : s(ss) {}\n        bool higher(int a, int b) { // true if a heavier than b\n            int c = s->cmpItem(a, b);\n            if (c == 0) return a > b;\n            return c > 0;\n        }\n        void push(int x) {\n            h.push_back(x);\n            int i = (int)h.size() - 1;\n            while (i > 0) {\n                int p = (i - 1) / 2;\n                if (!higher(h[i], h[p])) break;\n                swap(h[i], h[p]);\n                i = p;\n            }\n        }\n        int pop() {\n            int ret = h[0];\n            h[0] = h.back();\n            h.pop_back();\n            int n = (int)h.size();\n            int i = 0;\n            while (true) {\n                int l = 2*i + 1, r = 2*i + 2;\n                if (l >= n) break;\n                int best = l;\n                if (r < n && higher(h[r], h[l])) best = r;\n                if (!higher(h[best], h[i])) break;\n                swap(h[best], h[i]);\n                i = best;\n            }\n            return ret;\n        }\n        bool empty() const { return h.empty(); }\n    };\n\n    // Pivot bucketing for remaining items (heavy->light), bounded by cmpLimit through cmpItem fallback.\n    vector<int> approxOrderHeavyByPivots(vector<int> vec) {\n        int n = (int)vec.size();\n        if (n <= 1) return vec;\n\n        for (int i = n - 1; i > 0; i--) swap(vec[i], vec[rng.nextInt(0, i)]);\n\n        auto costForP = [&](int P) -> int {\n            if (P <= 1) return 0;\n            int lg = ceil_log2(P);\n            return P * lg + (n - P) * lg;\n        };\n\n        int remaining = max(0, cmpLimit - used);\n        int P = 2;\n        for (int cand : {32, 16, 8, 4, 2}) {\n            if (cand <= n && costForP(cand) <= remaining) { P = cand; break; }\n        }\n        if (P > n) P = n;\n        if (P < 2) return vec;\n\n        vector<int> piv(vec.begin(), vec.begin() + P);\n        vector<int> rest(vec.begin() + P, vec.end());\n\n        // insertion sort pivots ascending\n        for (int i = 1; i < P; i++) {\n            int x = piv[i];\n            int j = i - 1;\n            while (j >= 0) {\n                int c = cmpItem(piv[j], x);\n                if (c <= 0) break;\n                piv[j + 1] = piv[j];\n                j--;\n            }\n            piv[j + 1] = x;\n        }\n\n        vector<vector<int>> bucket(P + 1);\n        for (int x : rest) {\n            int lo = 0, hi = P;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                int c = cmpItem(x, piv[mid]);\n                if (c < 0) hi = mid;\n                else lo = mid + 1;\n            }\n            bucket[lo].push_back(x);\n        }\n\n        for (auto &b : bucket) {\n            for (int i = (int)b.size() - 1; i > 0; i--) swap(b[i], b[rng.nextInt(0, i)]);\n        }\n\n        vector<int> order;\n        order.reserve(n);\n        for (int j = P; j >= 1; j--) {\n            for (int x : bucket[j]) order.push_back(x);\n            order.push_back(piv[j - 1]);\n        }\n        for (int x : bucket[0]) order.push_back(x);\n\n        // ensure permutation of vec\n        vector<char> seen(N, 0);\n        vector<int> fixed;\n        fixed.reserve(n);\n        for (int x : order) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n        for (int x : vec) if (!seen[x]) fixed.push_back(x);\n        return fixed;\n    }\n\n    void moveItem(int item, int from, int to) {\n        auto &vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); i++) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        ans[item] = to;\n    }\n\n    int trueLightestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '>') best = i;\n        }\n        return best;\n    }\n    int trueHeaviestBin() {\n        int best = 0;\n        for (int i = 1; i < D && used < Q; i++) {\n            char r = querySets(bins[best], bins[i]);\n            if (r == '<') best = i;\n        }\n        return best;\n    }\n\n    static int argminSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] < s[idx]) idx = i;\n        return idx;\n    }\n    static int argmaxSum(const vector<long long>& s) {\n        int idx = 0;\n        for (int i = 1; i < (int)s.size(); i++) if (s[i] > s[idx]) idx = i;\n        return idx;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        unsigned long long seed = 1234567ULL;\n        seed ^= (unsigned long long)N * 1000003ULL;\n        seed ^= (unsigned long long)D * 10007ULL;\n        seed ^= (unsigned long long)Q * 97ULL;\n        rng = XorShift(seed);\n\n        used = 0;\n        bins.assign(D, {});\n        ans.assign(N, 0);\n        itemCmp.assign(N, vector<int8_t>(N, 2));\n\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        for (int i = N - 1; i > 0; i--) swap(items[i], items[rng.nextInt(0, i)]);\n\n        // ---- Budget split: keep enough for refinement, but not destroy ordering quality ----\n        int reserveImprove = max(2 * (D - 1) + 30, Q / 4);\n        reserveImprove = min(reserveImprove, 900);\n        int budgetOrder = Q - reserveImprove;\n\n        // Need at least N-1 queries to build a tournament; if not, just use all.\n        budgetOrder = max(budgetOrder, N - 1);\n        budgetOrder = min(budgetOrder, Q);\n        reserveImprove = Q - budgetOrder;\n\n        cmpLimit = budgetOrder;\n\n        // ---- Ordering: tournament top extraction + pivots for rest ----\n        vector<vector<int>> beaten(N);\n        int maxItem = buildTournament(items, beaten);\n\n        // Extract top-K (more for larger Q)\n        int Ktarget = min(N, max(2 * D, (Q >= 8 * N ? 4 * D : 2 * D)));\n        vector<int> heavyPrefix;\n        heavyPrefix.reserve(Ktarget);\n\n        vector<char> picked(N, 0);\n        MaxHeap heap(this);\n        heap.push(maxItem);\n        while (!heap.empty() && (int)heavyPrefix.size() < Ktarget && used < cmpLimit) {\n            int x = heap.pop();\n            if (picked[x]) continue;\n            picked[x] = 1;\n            heavyPrefix.push_back(x);\n            for (int y : beaten[x]) if (!picked[y]) heap.push(y);\n        }\n\n        vector<int> rest;\n        rest.reserve(N);\n        for (int x : items) if (!picked[x]) rest.push_back(x);\n\n        vector<int> orderHeavyToLight = heavyPrefix;\n        if (!rest.empty()) {\n            vector<int> approxRest = approxOrderHeavyByPivots(rest);\n            orderHeavyToLight.insert(orderHeavyToLight.end(), approxRest.begin(), approxRest.end());\n        }\n\n        // ensure permutation\n        {\n            vector<char> seen(N, 0);\n            vector<int> fixed;\n            fixed.reserve(N);\n            for (int x : orderHeavyToLight) if (!seen[x]) { seen[x] = 1; fixed.push_back(x); }\n            for (int x : items) if (!seen[x]) fixed.push_back(x);\n            orderHeavyToLight.swap(fixed);\n        }\n\n        // ---- Estimated weights from ranks (compressed heavy tail) ----\n        vector<int> orderLightToHeavy(orderHeavyToLight.rbegin(), orderHeavyToLight.rend());\n\n        const long double lambda = 1e-5L;\n        long long M = (long long)100000 * N / D;\n\n        // compress: w = (-ln(1-p)/lambda)^alpha\n        const long double alpha = 0.80L;\n\n        vector<long long> rankW(N, 1);\n        for (int r = 0; r < N; r++) {\n            long double p = (r + 0.5L) / (long double)N;\n            long double base = -logl(1.0L - p) / lambda;\n            long double v = powl(base, alpha);\n            long long w = (long long) llround((double)v);\n            w = clamp_ll(w, 1, M);\n            rankW[r] = w;\n        }\n        // enforce monotone and cap growth except for top few ranks\n        for (int r = 1; r < N; r++) rankW[r] = max(rankW[r], rankW[r - 1]);\n        int protectTop = min(N, max(10, 2 * D)); // keep steepness only at very top\n        for (int r = 1; r < N - protectTop; r++) {\n            long long cap = rankW[r - 1] + max(10LL, rankW[r - 1] / 4); // +25%\n            if (rankW[r] > cap) rankW[r] = cap;\n        }\n        vector<long long> estW(N, 1);\n        for (int r = 0; r < N; r++) estW[orderLightToHeavy[r]] = rankW[r];\n\n        // ---- Initial partition: LPT on estW ----\n        bins.assign(D, {});\n        vector<long long> sumEst(D, 0);\n        ans.assign(N, 0);\n\n        // Seed with top D items\n        for (int b = 0; b < D; b++) {\n            int it = orderHeavyToLight[b];\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n        }\n\n        struct Node { long long s; int b; };\n        struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.s > b.s; } };\n        priority_queue<Node, vector<Node>, Cmp> pq;\n        for (int b = 0; b < D; b++) pq.push({sumEst[b], b});\n\n        for (int idx = D; idx < N; idx++) {\n            int it = orderHeavyToLight[idx];\n            auto cur = pq.top(); pq.pop();\n            int b = cur.b;\n            bins[b].push_back(it);\n            ans[it] = b;\n            sumEst[b] += estW[it];\n            pq.push({sumEst[b], b});\n        }\n\n        // ---- Offline improvement on estW (moves + small swaps) ----\n        for (int iter = 0; iter < 8000; iter++) {\n            int H = argmaxSum(sumEst);\n            int L = argminSum(sumEst);\n            long long diff = sumEst[H] - sumEst[L];\n            if (diff <= 0) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // best move\n            int bestX = -1;\n            long long bestAbs = llabs(diff);\n            for (int x : bins[H]) {\n                long long nd = (sumEst[H] - estW[x]) - (sumEst[L] + estW[x]);\n                long long absd = llabs(nd);\n                if (absd < bestAbs) { bestAbs = absd; bestX = x; }\n            }\n            if (bestX != -1) {\n                sumEst[H] -= estW[bestX];\n                sumEst[L] += estW[bestX];\n                moveItem(bestX, H, L);\n                continue;\n            }\n\n            // small swap candidates\n            vector<int> candH = bins[H], candL = bins[L];\n            sort(candH.begin(), candH.end(), [&](int a, int b){ return estW[a] > estW[b]; });\n            sort(candL.begin(), candL.end(), [&](int a, int b){ return estW[a] < estW[b]; });\n            int takeH = min(3, (int)candH.size());\n            int takeL = min(3, (int)candL.size());\n\n            int bestA = -1, bestB = -1;\n            bestAbs = llabs(diff);\n            for (int i = 0; i < takeH; i++) for (int j = 0; j < takeL; j++) {\n                int a = candH[i], b = candL[j];\n                long long nd = (sumEst[H] - estW[a] + estW[b]) - (sumEst[L] - estW[b] + estW[a]);\n                long long absd = llabs(nd);\n                if (absd < bestAbs) { bestAbs = absd; bestA = a; bestB = b; }\n            }\n            if (bestA == -1) break;\n\n            sumEst[H] = sumEst[H] - estW[bestA] + estW[bestB];\n            sumEst[L] = sumEst[L] - estW[bestB] + estW[bestA];\n            for (int &x : bins[H]) if (x == bestA) { x = bestB; break; }\n            for (int &x : bins[L]) if (x == bestB) { x = bestA; break; }\n            ans[bestA] = L;\n            ans[bestB] = H;\n        }\n\n        // ---- Interactive refinement (use remaining queries only here) ----\n        cmpLimit = Q; // allow cmpItem again if we need it (rare)\n\n        while (used < Q) {\n            int remQ = Q - used;\n            if (remQ < 2 * (D - 1) + 2) break; // need extremes + at least 1 probe\n\n            int L = trueLightestBin();\n            if (used >= Q) break;\n            int H = trueHeaviestBin();\n            if (used >= Q) break;\n            if (L == H) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // Try to move an item x from H to L.\n            // Use binary-search-like probes on items sorted by estW.\n            vector<int> cand = bins[H];\n            sort(cand.begin(), cand.end(), [&](int a, int b){ return estW[a] < estW[b]; }); // light..heavy\n\n            int lo = 0, hi = (int)cand.size() - 1;\n            int bestEq = -1;\n            int bestStill = -1;   // r='>'  (newH > newL) => x too light\n            int bestOver = -1;    // r='<'  (newH < newL) => x too heavy\n            long double bestPredAbs = 1e100L;\n            int bestByPred = -1;\n\n            int probes = min(6, Q - used);\n            for (int step = 0; step < probes && lo <= hi && used < Q; step++) {\n                int mid = (lo + hi) >> 1;\n                int x = cand[mid];\n\n                // Build A = H \\ {x}, B = L U {x}\n                vector<int> A;\n                A.reserve(bins[H].size() - 1);\n                for (int y : bins[H]) if (y != x) A.push_back(y);\n                if (A.empty()) break;\n                vector<int> B = bins[L];\n                B.push_back(x);\n\n                char r = querySets(A, B);\n\n                long long pred = (sumEst[H] - estW[x]) - (sumEst[L] + estW[x]);\n                long double ap = fabsl((long double)pred);\n                if (ap < bestPredAbs) { bestPredAbs = ap; bestByPred = x; }\n\n                if (r == '=') { bestEq = x; break; }\n                if (r == '>') { bestStill = x; lo = mid + 1; } // need heavier x\n                else { bestOver = x; hi = mid - 1; }           // need lighter x\n            }\n\n            int chosen = -1;\n            if (bestEq != -1) chosen = bestEq;\n            else if (bestByPred != -1) chosen = bestByPred;\n            else if (bestStill != -1) chosen = bestStill;\n            else chosen = bestOver;\n\n            if (chosen == -1) break;\n            if ((int)bins[H].size() <= 1) break;\n\n            // Apply move (update estimated sums)\n            sumEst[H] -= estW[chosen];\n            sumEst[L] += estW[chosen];\n            moveItem(chosen, H, L);\n        }\n\n        // Dummy queries to reach exactly Q\n        while (used < Q) querySets(vector<int>{0}, vector<int>{1});\n\n        // Final clamp\n        for (int i = 0; i < N; i++) if (ans[i] < 0 || ans[i] >= D) ans[i] = 0;\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << \"\\n\";\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 200;\nstatic constexpr int M = 10;\nstatic constexpr int INF = INT_MAX;\n\nstruct Weights {\n    double wHeight = 0.06;\n    double wMinUrg = 230.0;\n    double wTopUrg = 85.0;\n    double wMinAtTopExtra = 260.0;\n\n    double badTopBase = 4200.0;\n    double badTopPerCnt = 220.0;     // per moved item that is > dest.top\n    double badMinBase = 2600.0;\n    double badMinPerCnt = 260.0;     // per moved item that is > dest.min (scaled by urgency)\n\n    double emptyReserve = 35.0;\n\n    int lookahead = 14;      // simulation removals\n    int destCand = 6;        // destinations tried per action\n    int cmax = 6;            // max chunk size (top peeling) considered\n};\n\nstruct Result {\n    long long energy = (1LL<<60);\n    vector<pair<int,int>> ops;\n};\n\nstatic inline uint64_t xorshift64(uint64_t &x) {\n    x ^= x << 7;\n    x ^= x >> 9;\n    return x;\n}\n\nstruct State {\n    array<array<int, N>, M> a{};\n    array<int, M> sz{};\n\n    array<int, N + 1> posS{};\n    array<int, N + 1> posI{};\n\n    array<int, M> top{};\n    array<int, M> mn{};\n    array<int, M> posMinFromTop{};\n\n    void recalc(int i) {\n        int h = sz[i];\n        if (h == 0) {\n            top[i] = INF;\n            mn[i] = INF;\n            posMinFromTop[i] = 0;\n            return;\n        }\n        top[i] = a[i][h - 1];\n        int best = INF, bestIdx = 0;\n        for (int j = 0; j < h; j++) {\n            int v = a[i][j];\n            if (v < best) {\n                best = v;\n                bestIdx = j;\n            }\n        }\n        mn[i] = best;\n        posMinFromTop[i] = (h - 1) - bestIdx;\n    }\n\n    void initFromInput(const vector<vector<int>> &init) {\n        for (int i = 0; i < M; i++) {\n            sz[i] = (int)init[i].size();\n            for (int j = 0; j < sz[i]; j++) {\n                a[i][j] = init[i][j];\n                posS[a[i][j]] = i;\n                posI[a[i][j]] = j;\n            }\n        }\n        for (int i = 0; i < M; i++) recalc(i);\n    }\n\n    inline pair<int,int> locate(int v) const {\n        return {posS[v], posI[v]};\n    }\n    inline bool isOnTop(int v) const {\n        auto [s, idx] = locate(v);\n        return s >= 0 && idx == sz[s] - 1;\n    }\n\n    inline void popTop(int s) {\n        int v = a[s][sz[s] - 1];\n        sz[s]--;\n        posS[v] = -1;\n        posI[v] = -1;\n        recalc(s);\n    }\n\n    inline void moveSuffix(int s, int start, int d) {\n        int k = sz[s] - start;\n        int base = sz[d];\n        for (int i = 0; i < k; i++) {\n            int x = a[s][start + i];\n            a[d][base + i] = x;\n            posS[x] = d;\n            posI[x] = base + i;\n        }\n        sz[d] += k;\n        sz[s] = start;\n        recalc(s);\n        recalc(d);\n    }\n};\n\nstruct MovePlan {\n    // operation 1: move suffix starting at 'start' from stack s to stack d\n    int s = -1;\n    int d = -1;\n    int start = -1;\n    int len = 0;\n    int v = -1;\n    long long eval = (1LL<<62);\n};\n\nstruct Solver {\n    State init;\n\n    explicit Solver(const vector<vector<int>> &st0) {\n        init.initFromInput(st0);\n    }\n\n    // Collect moved values into buf[0..len)\n    static inline int collectMoved(const State &st, int s, int start, int *buf) {\n        int len = st.sz[s] - start;\n        for (int i = 0; i < len; i++) buf[i] = st.a[s][start + i];\n        return len;\n    }\n\n    static inline int maxOfBuf(const int *buf, int len) {\n        int mx = 0;\n        for (int i = 0; i < len; i++) mx = max(mx, buf[i]);\n        return mx;\n    }\n\n    static inline double destPenaltyWithBuf(\n        const State &st,\n        int t,\n        int s, int d,\n        const int *buf, int len,\n        int bufMax,\n        const Weights &w\n    ) {\n        if (d == s) return 1e100;\n\n        int h = st.sz[d];\n        if (h == 0) {\n            // safe but slightly reserved\n            return w.emptyReserve + w.wHeight * double(len);\n        }\n\n        int top = st.top[d];\n        int mn = st.mn[d];\n        int posMin = st.posMinFromTop[d];\n\n        double deltaMin = double(mn - t);\n        double deltaTop = double(top - t);\n        if (deltaMin < 1.0) deltaMin = 1.0;\n        if (deltaTop < 1.0) deltaTop = 1.0;\n\n        // counts of \"blocking\" items after placing buf on destination\n        int cntAboveTop = 0;\n        int cntAboveMin = 0;\n        if (top != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > top) cntAboveTop++;\n        }\n        if (mn != INF) {\n            for (int i = 0; i < len; i++) if (buf[i] > mn) cntAboveMin++;\n        }\n\n        double p = 0.0;\n        p += w.wHeight * double(h + len);\n        p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n        p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n\n        if (posMin == 0) {\n            p += w.wMinAtTopExtra * double(len + 1) / (deltaMin + 1.0);\n        }\n\n        // Strong penalties when we bury a smaller top/min under larger moved values\n        if (cntAboveTop > 0) {\n            // also factor severity by how much bigger the move max is than top (mildly)\n            p += w.badTopBase + w.badTopPerCnt * cntAboveTop + 2.0 * max(0, bufMax - top);\n        }\n        if (cntAboveMin > 0) {\n            p += (w.badMinBase + w.badMinPerCnt * cntAboveMin) / (deltaMin + 1.0);\n        }\n\n        return p;\n    }\n\n    static int chooseDestBase(const State &st, int t, int s, int start, const Weights &w) {\n        int len = st.sz[s] - start;\n        int mx = 0;\n        for (int i = start; i < st.sz[s]; i++) mx = max(mx, st.a[s][i]);\n\n        // safe stack: mn > mx\n        int bestSafe = -1;\n        int bestH = INF;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > mx) {\n                int h = st.sz[d];\n                if (h < bestH) {\n                    bestH = h;\n                    bestSafe = d;\n                }\n            }\n        }\n        if (bestSafe != -1) return bestSafe;\n\n        // otherwise minimize a cheap proxy\n        double bestP = 1e100;\n        int bestD = (s + 1) % M;\n        for (int d = 0; d < M; d++) if (d != s) {\n            int h = st.sz[d];\n            int top = st.top[d];\n            int mn = st.mn[d];\n            double deltaMin = max(1.0, double(mn - t));\n            double deltaTop = max(1.0, double(top - t));\n            double p = 0.0;\n            if (h == 0) p += w.emptyReserve;\n            p += w.wHeight * double(h + len);\n            p += w.wMinUrg * double(len) / (deltaMin + 1.0);\n            p += w.wTopUrg * double(len) / (deltaTop + 1.0);\n            if (top < mx) p += w.badTopBase;\n            if (mn < mx) p += w.badMinBase / (deltaMin + 1.0);\n            if (p < bestP) { bestP = p; bestD = d; }\n        }\n        return bestD;\n    }\n\n    static long long simulateEnergy(State st, int tStart, int maxRemovals, const Weights &w) {\n        long long e = 0;\n        int t = tStart;\n        int removed = 0;\n\n        while (t <= N && removed < maxRemovals) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                st.popTop(s);\n                t++;\n                removed++;\n            } else {\n                int start = idx + 1;\n                int len = st.sz[s] - start;\n                int d = chooseDestBase(st, t, s, start, w);\n                st.moveSuffix(s, start, d);\n                e += (long long)len + 1;\n            }\n        }\n        return e;\n    }\n\n    // Decide the next move when t is not on top:\n    // either move whole above-t pile, or peel top c boxes, using 1-step search + lookahead.\n    static MovePlan decideMove(State const &st, int t, const Weights &w, uint64_t &rng, int opsLeft) {\n        auto [s, idx] = st.locate(t);\n        int kTotal = st.sz[s] - idx - 1;\n\n        MovePlan best;\n        best.eval = (1LL<<62);\n\n        // If operation budget is tight, avoid peeling.\n        bool tight = (opsLeft < 250);\n\n        // Precompute whole-pile info\n        int bufAll[N];\n        int startAll = idx + 1;\n        int lenAll = collectMoved(st, s, startAll, bufAll);\n        int maxAll = maxOfBuf(bufAll, lenAll);\n\n        bool existsSafeForAll = false;\n        for (int d = 0; d < M; d++) if (d != s) {\n            if (st.mn[d] > maxAll) { existsSafeForAll = true; break; }\n        }\n\n        // Gate: peeling search mainly when whole move has no safe destination or pile is small\n        bool doPeelSearch = (!tight) && (!existsSafeForAll || kTotal <= 10);\n\n        // Candidate actions: always include whole move, plus top-c peel moves if enabled\n        vector<pair<int,int>> actions; // (start, len)\n        actions.push_back({startAll, lenAll});\n        if (doPeelSearch) {\n            int cmax = min(w.cmax, kTotal);\n            for (int c = 1; c <= cmax; c++) {\n                int start = st.sz[s] - c;\n                if (start <= idx) continue; // must not include t\n                actions.push_back({start, c});\n            }\n        }\n\n        // Evaluate each action by trying best few destinations (ranked by penalty) and simulating\n        for (auto [start, len] : actions) {\n            int buf[N];\n            int got = collectMoved(st, s, start, buf);\n            (void)got;\n            int bufMax = maxOfBuf(buf, len);\n\n            // Rank destinations\n            vector<pair<double,int>> ranked;\n            ranked.reserve(M - 1);\n            for (int d = 0; d < M; d++) if (d != s) {\n                double p = destPenaltyWithBuf(st, t, s, d, buf, len, bufMax, w);\n                // tiny noise to diversify between trials\n                p += double(int(xorshift64(rng) % 1000)) * 1e-9;\n                ranked.push_back({p, d});\n            }\n            sort(ranked.begin(), ranked.end());\n\n            int D = min(w.destCand, (int)ranked.size());\n            for (int i = 0; i < D; i++) {\n                int d = ranked[i].second;\n                State st2 = st;\n                st2.moveSuffix(s, start, d);\n                long long score = (long long)len + 1;\n                score += simulateEnergy(st2, t, w.lookahead, w);\n\n                // mild bias: avoid excessive peeling unless it helps\n                if (len <= w.cmax && len != lenAll) score += 1; // tiny +1 (not energy), just tie-break\n\n                if (score < best.eval) {\n                    best.eval = score;\n                    best.s = s;\n                    best.d = d;\n                    best.start = start;\n                    best.len = len;\n                    best.v = st.a[s][start];\n                }\n            }\n        }\n\n        // Fallback (shouldn't happen)\n        if (best.s < 0) {\n            best.s = s;\n            best.start = startAll;\n            best.len = lenAll;\n            best.v = st.a[s][startAll];\n            best.d = (s + 1) % M;\n            best.eval = (long long)lenAll + 1;\n        }\n        return best;\n    }\n\n    Result run(const Weights &w, uint64_t seed) {\n        uint64_t rng = seed;\n        State st = init;\n\n        vector<pair<int,int>> ops;\n        ops.reserve(2500);\n\n        long long energy = 0;\n        int t = 1;\n\n        while (t <= N) {\n            auto [s, idx] = st.locate(t);\n            if (s < 0) break;\n\n            if (idx == st.sz[s] - 1) {\n                ops.push_back({t, 0});\n                st.popTop(s);\n                t++;\n            } else {\n                int opsLeft = 5000 - (int)ops.size();\n                MovePlan mv = decideMove(st, t, w, rng, opsLeft);\n\n                ops.push_back({mv.v, mv.d + 1});\n                st.moveSuffix(mv.s, mv.start, mv.d);\n                energy += (long long)mv.len + 1;\n            }\n\n            if ((int)ops.size() > 5000) break;\n        }\n\n        return Result{energy, std::move(ops)};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n    vector<vector<int>> initStacks(M);\n    for (int i = 0; i < M; i++) {\n        initStacks[i].resize(n / m);\n        for (int j = 0; j < n / m; j++) cin >> initStacks[i][j];\n    }\n\n    Solver solver(initStacks);\n\n    Weights base;\n\n    auto t0 = chrono::high_resolution_clock::now();\n    uint64_t baseSeed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n\n    Result best;\n    best.energy = (1LL<<60);\n\n    int trials = 0;\n    while (true) {\n        auto now = chrono::high_resolution_clock::now();\n        double elapsed = chrono::duration<double>(now - t0).count();\n        if (elapsed > 1.93) break;\n\n        Weights w = base;\n\n        uint64_t seed = baseSeed + 0x9e3779b97f4a7c15ULL * (uint64_t)trials;\n        uint64_t rng = seed;\n\n        auto rand01 = [&]() -> double {\n            return (double)(xorshift64(rng) % 1000000) / 1000000.0;\n        };\n        auto mult = [&](double x, double lo, double hi) {\n            return x * (lo + (hi - lo) * rand01());\n        };\n\n        if (trials > 0) {\n            w.wHeight = mult(w.wHeight, 0.7, 1.4);\n            w.wMinUrg = mult(w.wMinUrg, 0.75, 1.35);\n            w.wTopUrg = mult(w.wTopUrg, 0.75, 1.35);\n            w.wMinAtTopExtra = mult(w.wMinAtTopExtra, 0.75, 1.45);\n\n            w.badTopBase = mult(w.badTopBase, 0.7, 1.4);\n            w.badTopPerCnt = mult(w.badTopPerCnt, 0.7, 1.6);\n\n            w.badMinBase = mult(w.badMinBase, 0.7, 1.5);\n            w.badMinPerCnt = mult(w.badMinPerCnt, 0.7, 1.6);\n\n            w.emptyReserve = mult(w.emptyReserve, 0.6, 1.6);\n\n            // vary lookahead slightly\n            double r = rand01();\n            if (r < 0.25) w.lookahead = 12;\n            else if (r < 0.55) w.lookahead = 14;\n            else w.lookahead = 16;\n\n            // chunking aggressiveness\n            double r2 = rand01();\n            if (r2 < 0.30) w.cmax = 5;\n            else if (r2 < 0.70) w.cmax = 6;\n            else w.cmax = 7;\n\n            // destination candidates\n            double r3 = rand01();\n            if (r3 < 0.30) w.destCand = 5;\n            else if (r3 < 0.75) w.destCand = 6;\n            else w.destCand = 7;\n        }\n\n        Result cur = solver.run(w, seed);\n        if ((int)cur.ops.size() <= 5000 && cur.energy < best.energy) {\n            best = std::move(cur);\n        }\n\n        trials++;\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << \" \" << i << \"\\n\";\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline char oppositeDir(char c){\n    if(c=='U') return 'D';\n    if(c=='D') return 'U';\n    if(c=='L') return 'R';\n    return 'L';\n}\nstatic inline int dirId(char c){\n    if(c=='U') return 0;\n    if(c=='D') return 1;\n    if(c=='L') return 2;\n    return 3;\n}\nstatic const char DIRCH[4] = {'U','D','L','R'};\n\nstruct Timer{\n    chrono::steady_clock::time_point st;\n    Timer(): st(chrono::steady_clock::now()){}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct XorShift{\n    uint64_t x=88172645463325252ull;\n    explicit XorShift(uint64_t seed=0){ if(seed) x=seed; }\n    uint64_t next(){\n        x ^= x<<7;\n        x ^= x>>9;\n        return x;\n    }\n    int nextInt(int lo,int hi){\n        return lo + (int)(next() % (uint64_t)(hi-lo+1));\n    }\n};\n\nstruct Edge{\n    int to;\n    int eid;\n    char mv;\n};\n\nstruct AnalysisResult{\n    bool ok=false;\n    long long sumSq=(1LL<<62);\n    long double metric=1e100L;\n    vector<int> pos;          // size L+1, pos[0]=0, pos[i+1]=arrival after i-th move\n    vector<int> first, last;\n    vector<int> bestGapLen;\n    vector<int> bestGapStart;\n};\n\nstruct Solver{\n    int N,V;\n    vector<string> h,v;\n    vector<int> d;\n    vector<array<int,4>> nxt;\n\n    vector<vector<Edge>> g;\n    vector<int> eu, ev;\n    int E=0;\n\n    // all-pairs distances\n    vector<uint16_t> distAll;\n    static constexpr uint16_t INF = 65535;\n    inline uint16_t distUV(int u,int v) const { return distAll[(size_t)u*V + v]; }\n\n    // BCC (edge-stack)\n    vector<int> disc, low;\n    vector<char> isArt;\n    vector<int> estack;\n    vector<vector<int>> bccEdges;\n    vector<vector<int>> bccVerts;\n    vector<int> edgeBcc;\n    vector<vector<int>> belongs;\n    int B=0, A=0;\n    vector<int> artIndex;\n\n    // block-cut tree for portal\n    vector<vector<pair<int,int>>> bcTree;\n    vector<int> parentNode, parentVia;\n    vector<int> blockPortal;\n    vector<long long> blockWeight;\n\n    // precomputed block tours\n    vector<vector<int>> blockTopNodes;\n    vector<string> blockTour;\n\n    // restricted BFS buffers (only for precompute)\n    vector<int> rDist, rPrev;\n    vector<char> rPrevMove;\n\n    Solver(){\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n    }\n\n    int id(int i,int j) const { return i*N + j; }\n\n    void readInput(){\n        cin >> N;\n        V = N*N;\n        h.resize(N-1);\n        v.resize(N);\n        for(int i=0;i<N-1;i++) cin >> h[i];\n        for(int i=0;i<N;i++) cin >> v[i];\n        d.assign(V,0);\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int x; cin >> x;\n            d[id(i,j)] = x;\n        }\n        nxt.assign(V, array<int,4>{-1,-1,-1,-1});\n        for(int i=0;i<N;i++)for(int j=0;j<N;j++){\n            int u=id(i,j);\n            if(i>0   && h[i-1][j]=='0') nxt[u][0]=id(i-1,j);\n            if(i<N-1 && h[i][j]=='0')   nxt[u][1]=id(i+1,j);\n            if(j>0   && v[i][j-1]=='0') nxt[u][2]=id(i,j-1);\n            if(j<N-1 && v[i][j]=='0')   nxt[u][3]=id(i,j+1);\n        }\n\n        rDist.assign(V,-1);\n        rPrev.assign(V,-1);\n        rPrevMove.assign(V,0);\n    }\n\n    void buildGraph(){\n        g.assign(V, {});\n        eu.clear(); ev.clear();\n        for(int u=0;u<V;u++){\n            for(int k=0;k<4;k++){\n                int w=nxt[u][k];\n                if(w<0) continue;\n                if(u<w){\n                    int eid=(int)eu.size();\n                    eu.push_back(u);\n                    ev.push_back(w);\n                    char mv=DIRCH[k];\n                    g[u].push_back(Edge{w,eid,mv});\n                    g[w].push_back(Edge{u,eid,oppositeDir(mv)});\n                }\n            }\n        }\n        E=(int)eu.size();\n    }\n\n    void precomputeAllPairsDistances(){\n        distAll.assign((size_t)V*V, INF);\n        vector<int> dist(V,-1);\n        deque<int> q;\n        for(int s=0;s<V;s++){\n            fill(dist.begin(), dist.end(), -1);\n            dist[s]=0;\n            q.clear();\n            q.push_back(s);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(auto &e: g[u]){\n                    int w=e.to;\n                    if(dist[w]!=-1) continue;\n                    dist[w]=dist[u]+1;\n                    q.push_back(w);\n                }\n            }\n            size_t base=(size_t)s*V;\n            for(int vtx=0; vtx<V; vtx++){\n                distAll[base+vtx] = (dist[vtx]<0? INF : (uint16_t)dist[vtx]);\n            }\n        }\n    }\n\n    // Random shortest path using distance descent\n    string shortestPathMovesByDistRand(int s,int t, XorShift& rng) const {\n        if(s==t) return {};\n        uint16_t d0 = distUV(s,t);\n        if(d0==INF) return {};\n        string path;\n        path.reserve(d0);\n        int cur=s;\n        while(cur!=t){\n            uint16_t dc = distUV(cur,t);\n            int candDir[4], cc=0;\n            for(int k=0;k<4;k++){\n                int nx=nxt[cur][k];\n                if(nx<0) continue;\n                uint16_t dn = distUV(nx,t);\n                if(dn + 1 == dc){\n                    candDir[cc++] = k;\n                }\n            }\n            if(cc==0) return {};\n            int pick = candDir[rng.nextInt(0, cc-1)];\n            path.push_back(DIRCH[pick]);\n            cur = nxt[cur][pick];\n        }\n        return path;\n    }\n\n    // ----- BCC decomposition -----\n    void buildBCC(){\n        disc.assign(V,0);\n        low.assign(V,0);\n        isArt.assign(V,0);\n        edgeBcc.assign(E,-1);\n        bccEdges.clear();\n        bccVerts.clear();\n        estack.clear();\n        belongs.assign(V,{});\n        int tim=0;\n\n        auto addBCCfromEdges = [&](const vector<int>& edges){\n            if(edges.empty()) return;\n            int bid=(int)bccEdges.size();\n            bccEdges.push_back(edges);\n            for(int e: edges) edgeBcc[e]=bid;\n            vector<int> verts;\n            verts.reserve(edges.size()*2);\n            for(int e: edges){\n                verts.push_back(eu[e]);\n                verts.push_back(ev[e]);\n            }\n            sort(verts.begin(), verts.end());\n            verts.erase(unique(verts.begin(), verts.end()), verts.end());\n            bccVerts.push_back(verts);\n            for(int vtx: verts) belongs[vtx].push_back(bid);\n        };\n\n        auto popUntil = [&](int stopEid){\n            vector<int> edges;\n            while(true){\n                int e=estack.back(); estack.pop_back();\n                edges.push_back(e);\n                if(e==stopEid) break;\n            }\n            addBCCfromEdges(edges);\n        };\n        auto popAll = [&](){\n            vector<int> edges;\n            while(!estack.empty()){\n                edges.push_back(estack.back());\n                estack.pop_back();\n            }\n            addBCCfromEdges(edges);\n        };\n\n        function<void(int,int)> dfs = [&](int u,int peid){\n            disc[u]=low[u]=++tim;\n            int child=0;\n            for(auto &e: g[u]){\n                int vtx=e.to;\n                if(disc[vtx]==0){\n                    child++;\n                    estack.push_back(e.eid);\n                    dfs(vtx, e.eid);\n                    low[u]=min(low[u], low[vtx]);\n                    if(low[vtx] >= disc[u]){\n                        if(peid!=-1 || child>1) isArt[u]=1;\n                        popUntil(e.eid);\n                    }\n                }else if(e.eid!=peid && disc[vtx]<disc[u]){\n                    low[u]=min(low[u], disc[vtx]);\n                    estack.push_back(e.eid);\n                }\n            }\n        };\n\n        for(int s=0;s<V;s++){\n            if(disc[s]!=0) continue;\n            dfs(s,-1);\n            popAll();\n        }\n\n        B=(int)bccEdges.size();\n        artIndex.assign(V,-1);\n        A=0;\n        for(int vtx=0; vtx<V; vtx++){\n            if(isArt[vtx]) artIndex[vtx]=A++;\n        }\n    }\n\n    void buildBlockCutTree(){\n        int nodeCount=B+A;\n        bcTree.assign(nodeCount,{});\n        for(int bid=0; bid<B; bid++){\n            for(int vtx: bccVerts[bid]){\n                if(!isArt[vtx]) continue;\n                int an=B+artIndex[vtx];\n                bcTree[bid].push_back({an, vtx});\n                bcTree[an].push_back({bid, vtx});\n            }\n        }\n\n        int root;\n        if(isArt[0]) root=B+artIndex[0];\n        else root = belongs[0].empty()? 0 : belongs[0][0];\n\n        parentNode.assign(nodeCount,-1);\n        parentVia.assign(nodeCount,-1);\n        deque<int> q;\n        parentNode[root]=root;\n        parentVia[root]=0;\n        q.push_back(root);\n        while(!q.empty()){\n            int cur=q.front(); q.pop_front();\n            for(auto [nx, via]: bcTree[cur]){\n                if(parentNode[nx]!=-1) continue;\n                parentNode[nx]=cur;\n                parentVia[nx]=via;\n                q.push_back(nx);\n            }\n        }\n\n        blockPortal.assign(B,0);\n        for(int bid=0; bid<B; bid++){\n            if(parentNode[bid]==bid) blockPortal[bid]=0;\n            else blockPortal[bid]=parentVia[bid];\n        }\n\n        blockWeight.assign(B,0);\n        for(int bid=0; bid<B; bid++){\n            long long w=0;\n            for(int vtx: bccVerts[bid]) if(!isArt[vtx]) w += d[vtx];\n            if(w==0) for(int vtx: bccVerts[bid]) w += d[vtx];\n            blockWeight[bid]=w;\n        }\n    }\n\n    // restricted BFS inside a block (for precompute only)\n    void bfsRestricted(int s,int bid){\n        fill(rDist.begin(), rDist.end(), -1);\n        fill(rPrev.begin(), rPrev.end(), -1);\n        deque<int> q;\n        rDist[s]=0;\n        q.push_back(s);\n        while(!q.empty()){\n            int u=q.front(); q.pop_front();\n            for(auto &e: g[u]){\n                if(edgeBcc[e.eid]!=bid) continue;\n                int w=e.to;\n                if(rDist[w]!=-1) continue;\n                rDist[w]=rDist[u]+1;\n                rPrev[w]=u;\n                rPrevMove[w]=e.mv;\n                q.push_back(w);\n            }\n        }\n    }\n    string restrictedPath(int s,int t){\n        if(s==t) return {};\n        if(rDist[t]<0) return {};\n        string rev;\n        int cur=t;\n        while(cur!=s){\n            rev.push_back(rPrevMove[cur]);\n            cur=rPrev[cur];\n            if(cur<0) return {};\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    void precomputeBlockTours(){\n        blockTopNodes.assign(B,{});\n        blockTour.assign(B,\"\");\n\n        vector<pair<long long,int>> ord;\n        ord.reserve(B);\n        for(int bid=0; bid<B; bid++) ord.push_back({blockWeight[bid], bid});\n        sort(ord.begin(), ord.end(), greater<>());\n\n        int H=min<int>(28,(int)ord.size());\n        vector<char> heavy(B,0);\n        for(int i=0;i<H;i++) heavy[ord[i].second]=1;\n\n        for(int bid=0; bid<B; bid++){\n            if(!heavy[bid]) continue;\n            int portal=blockPortal[bid];\n\n            bool okPortal=false;\n            for(int vtx: bccVerts[bid]) if(vtx==portal){ okPortal=true; break; }\n            if(!okPortal) continue;\n\n            vector<int> verts=bccVerts[bid];\n            sort(verts.begin(), verts.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n\n            int K=min<int>(12,(int)verts.size());\n            verts.resize(K);\n            if(find(verts.begin(), verts.end(), portal)==verts.end()) verts.push_back(portal);\n\n            sort(verts.begin(), verts.end());\n            verts.erase(unique(verts.begin(), verts.end()), verts.end());\n            sort(verts.begin(), verts.end(), [&](int a,int b){\n                if(d[a]!=d[b]) return d[a]>d[b];\n                return a<b;\n            });\n            blockTopNodes[bid]=verts;\n\n            vector<int> targets=verts;\n            targets.erase(remove(targets.begin(), targets.end(), portal), targets.end());\n\n            string tour;\n            int cur=portal;\n            while(!targets.empty()){\n                bfsRestricted(cur, bid);\n                int best=-1, bestDist=INT_MAX, bestD=-1;\n                for(int t: targets){\n                    int dist=rDist[t];\n                    if(dist<0) continue;\n                    if(dist<bestDist || (dist==bestDist && d[t]>bestD)){\n                        bestDist=dist; bestD=d[t]; best=t;\n                    }\n                }\n                if(best==-1) break;\n                string p = restrictedPath(cur, best);\n                if(p.empty() && cur!=best) break;\n                tour += p;\n                cur = best;\n                targets.erase(remove(targets.begin(), targets.end(), best), targets.end());\n                if((int)tour.size() > 2200) break;\n            }\n            bfsRestricted(cur, bid);\n            string back = restrictedPath(cur, portal);\n            if(back.empty() && cur!=portal) continue;\n            tour += back;\n\n            if((int)tour.size() <= 2600) blockTour[bid]=tour;\n        }\n    }\n\n    // ----- base spanning tree / Euler / shortcut -----\n    void buildSpanningTree(vector<int>& parent, vector<char>& parentDir, vector<int>& order,\n                           XorShift& rng, int gamma, int noiseScale){\n        parent.assign(V,-1);\n        parentDir.assign(V,'?');\n        vector<int> depth(V,0);\n        vector<char> vis(V,0);\n        order.clear(); order.reserve(V);\n\n        struct Cand{ int key; int p; int x; char dir; };\n        struct Cmp{ bool operator()(const Cand& a,const Cand& b) const { return a.key < b.key; } };\n        priority_queue<Cand, vector<Cand>, Cmp> pq;\n\n        auto pushNei = [&](int u){\n            int du=depth[u];\n            for(int k=0;k<4;k++){\n                int w=nxt[u][k];\n                if(w<0||vis[w]) continue;\n                int noise = noiseScale ? rng.nextInt(0, noiseScale) : 0;\n                int key = d[w]*1024 - gamma*(du+1)*1024 + noise;\n                pq.push(Cand{key,u,w,DIRCH[k]});\n            }\n        };\n\n        vis[0]=1;\n        order.push_back(0);\n        pushNei(0);\n\n        while((int)order.size()<V){\n            if(pq.empty()) break;\n            auto c=pq.top(); pq.pop();\n            if(vis[c.x]) continue;\n            vis[c.x]=1;\n            parent[c.x]=c.p;\n            parentDir[c.x]=c.dir;\n            depth[c.x]=depth[c.p]+1;\n            order.push_back(c.x);\n            pushNei(c.x);\n        }\n\n        if((int)order.size()<V){\n            parent.assign(V,-1);\n            parentDir.assign(V,'?');\n            order.clear();\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent[w]=u;\n                    parentDir[w]=DIRCH[k];\n                    q.push_back(w);\n                    order.push_back(w);\n                }\n            }\n        }\n    }\n\n    string buildEulerRoute(const vector<int>& parent, const vector<char>& parentDir,\n                           const vector<int>& order, XorShift& rng, int childNoise){\n        vector<vector<int>> children(V);\n        for(int x=1;x<V;x++){\n            int p=parent[x];\n            if(p>=0) children[p].push_back(x);\n        }\n        vector<long long> sub(V);\n        for(int i=0;i<V;i++) sub[i]=d[i];\n        for(int idx=(int)order.size()-1; idx>=1; --idx){\n            int x=order[idx];\n            int p=parent[x];\n            if(p>=0) sub[p]+=sub[x];\n        }\n        for(int u=0;u<V;u++){\n            auto &ch=children[u];\n            sort(ch.begin(), ch.end(), [&](int a,int b){\n                long long ka=sub[a]*1024 + d[a]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                long long kb=sub[b]*1024 + d[b]*8 + (childNoise? (int)(rng.next()%childNoise):0);\n                if(ka!=kb) return ka>kb;\n                return a<b;\n            });\n        }\n        string route;\n        route.reserve(2*(V-1)+10);\n        function<void(int)> dfs=[&](int u){\n            for(int x: children[u]){\n                route.push_back(parentDir[x]);\n                dfs(x);\n                route.push_back(oppositeDir(parentDir[x]));\n            }\n        };\n        dfs(0);\n        return route;\n    }\n\n    bool simulatePositions(const string& route, vector<int>& pos) const {\n        int L=(int)route.size();\n        pos.assign(L+1,0);\n        int cur=0;\n        for(int i=0;i<L;i++){\n            int k=dirId(route[i]);\n            int nx=nxt[cur][k];\n            if(nx<0) return false;\n            cur=nx;\n            pos[i+1]=cur;\n        }\n        return cur==0;\n    }\n\n    vector<int> firstVisitOrderFromEuler(const string& euler) const {\n        vector<int> pos;\n        simulatePositions(euler, pos);\n        vector<char> seen(V,0);\n        vector<int> ord;\n        ord.reserve(V+1);\n        seen[0]=1;\n        ord.push_back(0);\n        for(int i=1;i<(int)pos.size();i++){\n            int vtx=pos[i];\n            if(!seen[vtx]){\n                seen[vtx]=1;\n                ord.push_back(vtx);\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++) if(!seen[vtx]) ord.push_back(vtx);\n        ord.push_back(0);\n        return ord;\n    }\n\n    string buildRouteFromOrderRand(const vector<int>& ord, XorShift& rng, int maxLen=100000) const {\n        string route;\n        for(int i=0;i+1<(int)ord.size();i++){\n            string p = shortestPathMovesByDistRand(ord[i], ord[i+1], rng);\n            if(p.empty() && ord[i]!=ord[i+1]) return {};\n            if((int)route.size() + (int)p.size() > maxLen) return {};\n            route += p;\n        }\n        return route;\n    }\n\n    // ----- metric (objective-equivalent) -----\n    AnalysisResult analyzeRoute(const string& route) const {\n        AnalysisResult res;\n        int L=(int)route.size();\n        if(L<=0) return res;\n        if(!simulatePositions(route, res.pos)) return res;\n\n        res.first.assign(V,-1);\n        res.last.assign(V,-1);\n        res.bestGapLen.assign(V,-1);\n        res.bestGapStart.assign(V,0);\n\n        long long sumSq=0;\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=res.pos[i+1];\n            if(res.first[vtx]==-1){\n                res.first[vtx]=res.last[vtx]=t;\n            }else{\n                int gap=t-res.last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                if(gap > res.bestGapLen[vtx]){\n                    res.bestGapLen[vtx]=gap;\n                    res.bestGapStart[vtx]=res.last[vtx];\n                }\n                res.last[vtx]=t;\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++){\n            if(res.first[vtx]==-1) return res;\n            int gap=(res.first[vtx]+L)-res.last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n            if(gap > res.bestGapLen[vtx]){\n                res.bestGapLen[vtx]=gap;\n                res.bestGapStart[vtx]=res.last[vtx];\n            }\n        }\n        res.sumSq=sumSq;\n        res.metric=(long double)sumSq/(long double)L;\n        res.ok=true;\n        return res;\n    }\n\n    long double computeMetric(const string& route, vector<int>& first, vector<int>& last) const {\n        int L=(int)route.size();\n        if(L<=0) return 1e100L;\n        vector<int> pos;\n        if(!simulatePositions(route, pos)) return 1e100L;\n\n        fill(first.begin(), first.end(), -1);\n        fill(last.begin(), last.end(), -1);\n        long long sumSq=0;\n\n        for(int i=0;i<L;i++){\n            int t=i;\n            int vtx=pos[i+1];\n            if(first[vtx]==-1) first[vtx]=last[vtx]=t;\n            else{\n                int gap=t-last[vtx];\n                sumSq += 1LL*d[vtx]*gap*gap;\n                last[vtx]=t;\n            }\n        }\n        for(int vtx=0; vtx<V; vtx++){\n            if(first[vtx]==-1) return 1e100L;\n            int gap=(first[vtx]+L)-last[vtx];\n            sumSq += 1LL*d[vtx]*gap*gap;\n        }\n        return (long double)sumSq/(long double)L;\n    }\n\n    // insertion position near midpoint of rep's best gap, minimizing dist(pos[p], target)\n    pair<int,int> chooseInsertPosNearGap(const AnalysisResult& ar, int repVtx, int targetVtx) const {\n        int L=(int)ar.pos.size()-1;\n        int startT=ar.bestGapStart[repVtx];\n        int len=ar.bestGapLen[repVtx];\n        long long midT=(long long)startT + len/2;\n        int baseP=(int)((midT + 1) % L);\n\n        int W=min(50, max(3, len/5));\n        int bestP=baseP;\n        int bestDist=INT_MAX;\n        int bestAbs=INT_MAX;\n\n        for(int off=-W; off<=W; off++){\n            int p=baseP+off;\n            p%=L; if(p<0) p+=L;\n            int at=ar.pos[p];\n            uint16_t dist=distUV(at, targetVtx);\n            if(dist==INF) continue;\n            int aoff=abs(off);\n            if((int)dist < bestDist || ((int)dist==bestDist && aoff < bestAbs)){\n                bestDist=(int)dist;\n                bestAbs=aoff;\n                bestP=p;\n            }\n        }\n        return {bestP, bestDist};\n    }\n\n    void improveByDetours(string& route, XorShift& rng, Timer& timer, double endTime){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        vector<int> tourBlocks;\n        for(int bid=0; bid<B; bid++){\n            if(!blockTour[bid].empty()) tourBlocks.push_back(bid);\n        }\n\n        while(timer.elapsed() < endTime){\n            AnalysisResult ar = analyzeRoute(route);\n            if(!ar.ok) break;\n            long double curMetric = ar.metric;\n            int L=(int)route.size();\n            if(L>=100000) break;\n\n            struct Cand{\n                int type; // 0 vertex, 1 block\n                int key;  // vtx or bid\n                int insertPos;\n                long long estBenefit;\n                int estAddLen;\n                long double ratio;\n            };\n            vector<Cand> cands;\n            cands.reserve(160);\n\n            // vertex candidates\n            vector<pair<long long,int>> vkeys;\n            vkeys.reserve(V);\n            for(int vtx=0; vtx<V; vtx++){\n                int ggap=ar.bestGapLen[vtx];\n                if(ggap<=1) continue;\n                vkeys.push_back({1LL*d[vtx]*ggap*ggap, vtx});\n            }\n            if(vkeys.empty()) break;\n            int Kv=min<int>(60,(int)vkeys.size());\n            nth_element(vkeys.begin(), vkeys.begin()+Kv, vkeys.end(),\n                        [&](auto& a, auto& b){ return a.first > b.first; });\n            vkeys.resize(Kv);\n            sort(vkeys.begin(), vkeys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n            for(auto [_, vtx] : vkeys){\n                if(timer.elapsed() >= endTime) break;\n                int ggap=ar.bestGapLen[vtx];\n                auto [p, dist] = chooseInsertPosNearGap(ar, vtx, vtx);\n                if(dist<=0) continue;\n                int addLen = 2*dist;\n                if(L + addLen > 100000) continue;\n                int a=ggap/2, b=ggap-a;\n                long long benefit = 1LL*d[vtx]*(1LL*ggap*ggap - 1LL*a*a - 1LL*b*b);\n                if(benefit<=0) continue;\n                cands.push_back(Cand{0, vtx, p, benefit, addLen, (long double)benefit/addLen});\n            }\n\n            // block candidates (dynamic hotness)\n            vector<pair<long long,int>> bkeys;\n            bkeys.reserve(tourBlocks.size());\n            for(int bid: tourBlocks){\n                long long hot=0;\n                for(int u: blockTopNodes[bid]){\n                    int ggap=ar.bestGapLen[u];\n                    hot += 1LL*d[u]*ggap*ggap;\n                }\n                if(hot>0) bkeys.push_back({hot, bid});\n            }\n            int Kb=min<int>(7,(int)bkeys.size());\n            if(Kb>0){\n                nth_element(bkeys.begin(), bkeys.begin()+Kb, bkeys.end(),\n                            [&](auto& a, auto& b){ return a.first > b.first; });\n                bkeys.resize(Kb);\n                sort(bkeys.begin(), bkeys.end(), [&](auto& a, auto& b){ return a.first > b.first; });\n\n                for(auto [_, bid] : bkeys){\n                    if(timer.elapsed() >= endTime) break;\n                    int portal=blockPortal[bid];\n                    const string& tour = blockTour[bid];\n\n                    int rep=portal;\n                    long long repKey=-1;\n                    for(int u: blockTopNodes[bid]){\n                        int ggap=ar.bestGapLen[u];\n                        long long kk=1LL*d[u]*ggap*ggap;\n                        if(kk>repKey){ repKey=kk; rep=u; }\n                    }\n                    if(repKey<=0) continue;\n\n                    auto [p, distToPortal] = chooseInsertPosNearGap(ar, rep, portal);\n                    if(distToPortal<=0) continue;\n                    int addLen = 2*distToPortal + (int)tour.size();\n                    if(L + addLen > 100000) continue;\n\n                    long long benefitSum=0;\n                    for(int u: blockTopNodes[bid]){\n                        int ggap=ar.bestGapLen[u];\n                        if(ggap<=1) continue;\n                        int a=ggap/2, b=ggap-a;\n                        benefitSum += 1LL*d[u]*(1LL*ggap*ggap - 1LL*a*a - 1LL*b*b);\n                    }\n                    if(benefitSum<=0) continue;\n\n                    cands.push_back(Cand{1, bid, p, benefitSum, addLen, (long double)benefitSum/addLen});\n                }\n            }\n\n            if(cands.empty()) break;\n            sort(cands.begin(), cands.end(), [&](const Cand& a, const Cand& b){\n                return a.ratio > b.ratio;\n            });\n\n            // Evaluate a handful, with 2 randomized variants each (more exploration at same cost level)\n            int M=min<int>(12,(int)cands.size());\n            int variantsVertex = 2;\n            int variantsBlock  = 1;\n\n            long double bestMetric=curMetric;\n            int bestPos=-1;\n            string bestDet;\n\n            for(int i=0;i<M;i++){\n                if(timer.elapsed() >= endTime) break;\n                const auto& c=cands[i];\n                int p=c.insertPos;\n                int startV=ar.pos[p];\n\n                int variants = (c.type==0? variantsVertex : variantsBlock);\n                for(int rep=0; rep<variants; rep++){\n                    if(timer.elapsed() >= endTime) break;\n                    string det;\n\n                    if(c.type==0){\n                        int vtx=c.key;\n                        string go  = shortestPathMovesByDistRand(startV, vtx, rng);\n                        if(go.empty() && startV!=vtx) continue;\n                        string ret = shortestPathMovesByDistRand(vtx, startV, rng);\n                        if(ret.empty() && startV!=vtx) continue;\n                        det.reserve(go.size()+ret.size());\n                        det += go;\n                        det += ret;\n                    }else{\n                        int bid=c.key;\n                        int portal=blockPortal[bid];\n                        const string& tour=blockTour[bid];\n\n                        string go  = shortestPathMovesByDistRand(startV, portal, rng);\n                        if(go.empty() && startV!=portal) continue;\n                        string ret = shortestPathMovesByDistRand(portal, startV, rng);\n                        if(ret.empty() && startV!=portal) continue;\n\n                        det.reserve(go.size() + tour.size() + ret.size());\n                        det += go;\n                        det += tour;\n                        det += ret;\n                    }\n\n                    if((int)route.size() + (int)det.size() > 100000) continue;\n\n                    route.insert((size_t)p, det);\n                    long double met = computeMetric(route, tmpFirst, tmpLast);\n                    route.erase((size_t)p, det.size());\n\n                    if(met + 1e-18L < bestMetric){\n                        bestMetric = met;\n                        bestPos = p;\n                        bestDet = std::move(det);\n                    }\n                }\n            }\n\n            if(bestPos==-1) break;\n            route.insert((size_t)bestPos, bestDet);\n        }\n    }\n\n    // greatly reduced simplifier (cheap attempts only)\n    void simplifyBacktracksLight(string& route, XorShift& rng, Timer& timer, double endTime){\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n        vector<int> pos;\n        for(int it=0; it<30 && timer.elapsed() < endTime; it++){\n            if(!simulatePositions(route, pos)) return;\n            int L=(int)route.size();\n            if(L<2) return;\n            int i = rng.nextInt(0, L-2);\n            if(oppositeDir(route[i]) != route[i+1]) continue;\n\n            long double base = computeMetric(route, tmpFirst, tmpLast);\n            string cand;\n            cand.reserve(L-2);\n            cand.append(route.begin(), route.begin()+i);\n            cand.append(route.begin()+i+2, route.end());\n            long double met = computeMetric(cand, tmpFirst, tmpLast);\n            if(met + 1e-18L < base){\n                route.swap(cand);\n            }\n        }\n    }\n\n    void solve(){\n        Timer timer;\n        double TL=1.95;\n        XorShift rng((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n        buildGraph();\n        precomputeAllPairsDistances();\n        buildBCC();\n        buildBlockCutTree();\n        precomputeBlockTours();\n\n        vector<int> tmpFirst(V,-1), tmpLast(V,-1);\n\n        string bestRoute;\n        long double bestMetric=1e100L;\n\n        int starts=7;\n        vector<int> parent, order;\n        vector<char> parentDir;\n\n        for(int s=0;s<starts;s++){\n            if(timer.elapsed() > TL) break;\n\n            int gamma = 8 + (s%5)*4;\n            int noiseScale = 8000 + s*2500;\n            int childNoise  = 1200 + s*800;\n\n            buildSpanningTree(parent, parentDir, order, rng, gamma, noiseScale);\n            string euler = buildEulerRoute(parent, parentDir, order, rng, childNoise);\n\n            vector<int> ord = firstVisitOrderFromEuler(euler);\n            // randomized shortest paths for base tour too\n            string route = buildRouteFromOrderRand(ord, rng, 100000);\n            if(route.empty()) route = euler;\n\n            double now=timer.elapsed();\n            double remain=max(0.0, TL-now);\n            double per = remain / max(1, starts - s);\n            double endTime = min(TL, now + per*0.965);\n\n            improveByDetours(route, rng, timer, endTime);\n            simplifyBacktracksLight(route, rng, timer, min(TL, endTime + 0.01));\n\n            long double met = computeMetric(route, tmpFirst, tmpLast);\n            if(met < bestMetric){\n                bestMetric = met;\n                bestRoute = std::move(route);\n            }\n        }\n\n        if(bestRoute.empty()){\n            // fallback BFS-tree Euler\n            vector<int> parent2(V,-1), order2;\n            vector<char> pd2(V,'?');\n            deque<int> q;\n            vector<char> seen(V,0);\n            seen[0]=1; q.push_back(0); order2.push_back(0);\n            while(!q.empty()){\n                int u=q.front(); q.pop_front();\n                for(int k=0;k<4;k++){\n                    int w=nxt[u][k];\n                    if(w<0||seen[w]) continue;\n                    seen[w]=1;\n                    parent2[w]=u;\n                    pd2[w]=DIRCH[k];\n                    q.push_back(w);\n                    order2.push_back(w);\n                }\n            }\n            // simple Euler\n            vector<vector<int>> children(V);\n            for(int x=1;x<V;x++){\n                int p=parent2[x];\n                if(p>=0) children[p].push_back(x);\n            }\n            string r;\n            function<void(int)> dfs=[&](int u){\n                for(int x: children[u]){\n                    r.push_back(pd2[x]);\n                    dfs(x);\n                    r.push_back(oppositeDir(pd2[x]));\n                }\n            };\n            dfs(0);\n            bestRoute = r;\n        }\n\n        cout << bestRoute << \"\\n\";\n    }\n};\n\nint main(){\n    Solver s;\n    s.readInput();\n    s.solve();\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static const auto t0 = steady_clock::now();\n    return duration<double>(steady_clock::now() - t0).count();\n}\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic inline uint64_t hash_perm(const vector<int>& p) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int x : p) h = h * 1000003ULL + (uint64_t)(x + 1);\n    return splitmix64(h);\n}\n\nstruct Candidate {\n    int approx;\n    vector<int> perm;\n    uint64_t h;\n};\n\nstatic inline void add_pool(vector<Candidate>& pool, int K, int approx, const vector<int>& perm) {\n    uint64_t h = hash_perm(perm);\n    for (auto &c : pool) {\n        if (c.h == h) {\n            if (approx < c.approx) { c.approx = approx; c.perm = perm; }\n            return;\n        }\n    }\n    if ((int)pool.size() < K) {\n        pool.push_back({approx, perm, h});\n        return;\n    }\n    int worst = 0;\n    for (int i = 1; i < (int)pool.size(); i++) if (pool[i].approx > pool[worst].approx) worst = i;\n    if (approx < pool[worst].approx) pool[worst] = {approx, perm, h};\n}\n\nstruct Policy {\n    enum Type { CAP_DET, CAP_HASH, MINCOST_DET } type;\n    int cap;       // CAP_* only\n    uint64_t seed; // CAP_HASH only\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    int si, sj;\n    cin >> si >> sj;\n    vector<string> grid(N);\n    for (int i = 0; i < N; i++) cin >> grid[i];\n    vector<string> t(M);\n    for (int i = 0; i < M; i++) cin >> t[i];\n\n    constexpr int NFIX = 15;\n    constexpr int V = NFIX * NFIX; // 225\n    auto cell_id = [&](int r, int c) { return r * N + c; };\n    int startCell = cell_id(si, sj);\n\n    array<int, V> letterAtCell{};\n    for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n        int id = cell_id(r, c);\n        letterAtCell[id] = grid[r][c] - 'A';\n    }\n\n    array<vector<int>, 26> cellsByLetter;\n    for (int id = 0; id < N * N; id++) cellsByLetter[letterAtCell[id]].push_back(id);\n\n    int maxOcc = 0;\n    for (int c = 0; c < 26; c++) maxOcc = max(maxOcc, (int)cellsByLetter[c].size());\n\n    // Manhattan dist between cells\n    vector<array<uint8_t, V>> distCell(V);\n    for (int a = 0; a < V; a++) {\n        int ar = a / N, ac = a % N;\n        for (int b = 0; b < V; b++) {\n            int br = b / N, bc = b % N;\n            distCell[a][b] = (uint8_t)(abs(ar - br) + abs(ac - bc));\n        }\n    }\n\n    // words as ints\n    vector<array<int,5>> w(M);\n    vector<int> lastL(M);\n    for (int i = 0; i < M; i++) {\n        for (int k = 0; k < 5; k++) w[i][k] = t[i][k] - 'A';\n        lastL[i] = w[i][4];\n    }\n\n    auto max_overlap = [&](int a, int b) -> int {\n        for (int l = 4; l >= 1; --l) {\n            bool ok = true;\n            for (int i = 0; i < l; i++) if (t[a][5 - l + i] != t[b][i]) { ok = false; break; }\n            if (ok) return l;\n        }\n        return 0;\n    };\n\n    vector<vector<uint8_t>> ovMax(M, vector<uint8_t>(M, 0));\n    for (int i = 0; i < M; i++) for (int j = 0; j < M; j++) if (i != j) {\n        ovMax[i][j] = (uint8_t)max_overlap(i, j);\n    }\n\n    // ---- Approx word typing costs (used for approximate edge weights) ----\n    vector<int> dp(maxOcc), ndp(maxOcc);\n\n    auto cost_type_from_cell = [&](int idx, int sCell, int from) -> int {\n        if (from >= 5) return 0;\n        const auto &ww = w[idx];\n\n        const auto &L0 = cellsByLetter[ww[from]];\n        int prevSize = (int)L0.size();\n        for (int i = 0; i < prevSize; i++) dp[i] = (int)distCell[sCell][L0[i]] + 1;\n\n        for (int k = from + 1; k < 5; k++) {\n            const auto &Lprev = cellsByLetter[ww[k-1]];\n            const auto &Lcur  = cellsByLetter[ww[k]];\n            int curSize = (int)Lcur.size();\n\n            for (int i = 0; i < curSize; i++) {\n                int best = INT_MAX;\n                int ccell = Lcur[i];\n                for (int j = 0; j < prevSize; j++) {\n                    int pcell = Lprev[j];\n                    int cand = dp[j] + (int)distCell[pcell][ccell] + 1;\n                    if (cand < best) best = cand;\n                }\n                ndp[i] = best;\n            }\n            for (int i = 0; i < curSize; i++) dp[i] = ndp[i];\n            prevSize = curSize;\n        }\n\n        int best = INT_MAX;\n        for (int i = 0; i < prevSize; i++) best = min(best, dp[i]);\n        return best;\n    };\n\n    vector<int> startCostWord(M, 0);\n    vector<array<int,26>> fromLetterCost(M);\n    vector<array<int,5>> overlapSuffixCost(M);\n    vector<int> fullFromCell(V);\n\n    for (int i = 0; i < M; i++) {\n        fromLetterCost[i].fill(INT_MAX);\n        overlapSuffixCost[i].fill(INT_MAX);\n\n        for (int s = 0; s < V; s++) fullFromCell[s] = cost_type_from_cell(i, s, 0);\n        startCostWord[i] = fullFromCell[startCell];\n\n        for (int s = 0; s < V; s++) {\n            int x = letterAtCell[s];\n            fromLetterCost[i][x] = min(fromLetterCost[i][x], fullFromCell[s]);\n        }\n\n        for (int l = 1; l <= 4; l++) {\n            int prevLetter = w[i][l-1];\n            int best = INT_MAX;\n            for (int s : cellsByLetter[prevLetter]) best = min(best, cost_type_from_cell(i, s, l));\n            overlapSuffixCost[i][l] = best;\n        }\n    }\n\n    auto build_edgeCost_cap = [&](int cap) {\n        vector<vector<int>> edge(M, vector<int>(M, 0));\n        for (int a = 0; a < M; a++) for (int b = 0; b < M; b++) if (a != b) {\n            int ov = min<int>(ovMax[a][b], cap);\n            edge[a][b] = (ov == 0 ? fromLetterCost[b][lastL[a]] : overlapSuffixCost[b][ov]);\n        }\n        return edge;\n    };\n\n    // MINCOST overlap choice per edge + edgeMin (permissive filter)\n    vector<vector<uint8_t>> bestOvMin(M, vector<uint8_t>(M, 0));\n    vector<vector<int>> edgeMin(M, vector<int>(M, 0));\n    for (int a = 0; a < M; a++) for (int b = 0; b < M; b++) if (a != b) {\n        int bestOv = 0;\n        int bestCost = fromLetterCost[b][lastL[a]];\n        int mx = (int)ovMax[a][b];\n        for (int ov = 1; ov <= mx; ov++) {\n            int c = overlapSuffixCost[b][ov];\n            if (c < bestCost) { bestCost = c; bestOv = ov; }\n        }\n        bestOvMin[a][b] = (uint8_t)bestOv;\n        edgeMin[a][b] = bestCost;\n    }\n\n    auto edge4 = build_edgeCost_cap(4);\n    auto edge2 = build_edgeCost_cap(2);\n    auto edge1 = build_edgeCost_cap(1);\n\n    // ---- Exact DP cost/path ----\n    vector<int> dpPrev(maxOcc), dpCur(maxOcc);\n\n    auto exact_cost_string = [&](const string& S) -> int {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        int prevSize = 0;\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int curSize = (int)layer.size();\n\n            if (k == 0) {\n                for (int i = 0; i < curSize; i++) dpCur[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                for (int i = 0; i < curSize; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    for (int j = 0; j < prevSize; j++) {\n                        int cand = dpPrev[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    dpCur[i] = best;\n                }\n            }\n            for (int i = 0; i < curSize; i++) dpPrev[i] = dpCur[i];\n            prevSize = curSize;\n        }\n        int lastSize = (int)cellsByLetter[S.back() - 'A'].size();\n        int best = INF;\n        for (int i = 0; i < lastSize; i++) best = min(best, dpPrev[i]);\n        return best;\n    };\n\n    auto exact_path_string = [&](const string& S) -> pair<int, vector<int>> {\n        const int INF = 1e9;\n        int L = (int)S.size();\n        vector<vector<int16_t>> parent(L);\n        vector<int> dpp, dpc;\n        dpp.reserve(maxOcc); dpc.reserve(maxOcc);\n\n        for (int k = 0; k < L; k++) {\n            int c = S[k] - 'A';\n            const auto &layer = cellsByLetter[c];\n            int mc = (int)layer.size();\n            dpc.assign(mc, INF);\n            parent[k].assign(mc, (int16_t)-1);\n\n            if (k == 0) {\n                for (int i = 0; i < mc; i++) dpc[i] = (int)distCell[startCell][layer[i]] + 1;\n            } else {\n                int pc = S[k-1] - 'A';\n                const auto &prevLayer = cellsByLetter[pc];\n                int mp = (int)prevLayer.size();\n                for (int i = 0; i < mc; i++) {\n                    int cc = layer[i];\n                    int best = INF;\n                    int16_t bestj = -1;\n                    for (int j = 0; j < mp; j++) {\n                        int cand = dpp[j] + (int)distCell[prevLayer[j]][cc] + 1;\n                        if (cand < best) { best = cand; bestj = (int16_t)j; }\n                    }\n                    dpc[i] = best;\n                    parent[k][i] = bestj;\n                }\n            }\n            dpp.swap(dpc);\n        }\n\n        int bestCost = INF, bestIdx = 0;\n        for (int i = 0; i < (int)dpp.size(); i++) if (dpp[i] < bestCost) { bestCost = dpp[i]; bestIdx = i; }\n\n        vector<int> path(L);\n        int idx = bestIdx;\n        for (int k = L - 1; k >= 0; k--) {\n            int c = S[k] - 'A';\n            path[k] = cellsByLetter[c][idx];\n            idx = parent[k][idx];\n        }\n        return {bestCost, path};\n    };\n\n    // RNG\n    mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    // Deterministic hashed overlap (biased to larger overlaps)\n    auto overlap_hash = [&](int a, int b, int cap, uint64_t seed) -> int {\n        int mx = (int)ovMax[a][b];\n        int C = min(mx, cap);\n        if (C <= 0) return 0;\n        uint64_t x = splitmix64(seed ^ (uint64_t)a * 1000003ULL ^ (uint64_t)b * 10007ULL);\n        uint64_t denom = (1ULL << (C + 1)) - 1ULL;\n        uint64_t r = x % denom;\n        uint64_t acc = 0;\n        for (int k = 0; k <= C; k++) {\n            acc += (1ULL << k);\n            if (r < acc) return k;\n        }\n        return C;\n    };\n\n    string Sbuf;\n    Sbuf.reserve(2200);\n\n    auto build_S_to = [&](const vector<int>& P, const Policy& pol, string& out) {\n        out.clear();\n        out += t[P[0]];\n        for (int i = 1; i < M; i++) {\n            int a = P[i-1], b = P[i];\n            int ov = 0;\n            if (pol.type == Policy::MINCOST_DET) ov = (int)bestOvMin[a][b];\n            else if (pol.type == Policy::CAP_DET) ov = min<int>(ovMax[a][b], pol.cap);\n            else ov = overlap_hash(a, b, pol.cap, pol.seed);\n            out.append(t[b].begin() + ov, t[b].end());\n        }\n    };\n\n    // diversified greedy start ranking\n    vector<int> startOrder(M);\n    iota(startOrder.begin(), startOrder.end(), 0);\n    sort(startOrder.begin(), startOrder.end(), [&](int a, int b){ return startCostWord[a] < startCostWord[b]; });\n\n    // SA with pool of best candidates\n    auto run_SA = [&](const vector<vector<int>>& edgeCost, double endTime, int poolK) {\n        auto link_cost = [&](int prev, int cur) -> int {\n            if (cur < 0) return 0;\n            if (prev < 0) return startCostWord[cur];\n            return edgeCost[prev][cur];\n        };\n        auto eval_perm = [&](const vector<int>& P) -> int {\n            long long cost = startCostWord[P[0]];\n            for (int i = 1; i < M; i++) cost += edgeCost[P[i-1]][P[i]];\n            return (int)cost;\n        };\n\n        auto greedy_init = [&]() -> vector<int> {\n            int K = min(14, M);\n            int sidx = startOrder[(int)(ur(rng) * K)];\n            vector<int> P;\n            P.reserve(M);\n            vector<char> used(M, 0);\n            P.push_back(sidx);\n            used[sidx] = 1;\n\n            for (int it = 1; it < M; it++) {\n                int cur = P.back();\n                int B = 3;\n                array<pair<int,int>, 3> best;\n                for (int b = 0; b < B; b++) best[b] = {INT_MAX, -1};\n\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeCost[cur][j];\n                    for (int b = 0; b < B; b++) {\n                        if (v < best[b].first) {\n                            for (int k = B - 1; k > b; k--) best[k] = best[k-1];\n                            best[b] = {v, j};\n                            break;\n                        }\n                    }\n                }\n                double r = ur(rng);\n                int pick = (r < 0.70 ? 0 : (r < 0.92 ? 1 : 2));\n                if (best[pick].second == -1) pick = 0;\n                int nxt = best[pick].second;\n                used[nxt] = 1;\n                P.push_back(nxt);\n            }\n            return P;\n        };\n\n        auto random_init = [&]() -> vector<int> {\n            vector<int> P(M);\n            iota(P.begin(), P.end(), 0);\n            shuffle(P.begin(), P.end(), rng);\n            return P;\n        };\n\n        auto delta_swap = [&](const vector<int>& P, int i, int j) -> int {\n            if (i == j) return 0;\n            if (i > j) swap(i, j);\n            int a = P[i], b = P[j];\n            auto get = [&](int k)->int{ if(k==i) return b; if(k==j) return a; return P[k]; };\n            auto contrib_at = [&](int k, bool after)->int{\n                if (k<0||k>=M) return 0;\n                int curv = after ? get(k) : P[k];\n                int prev = (k==0 ? -1 : (after ? get(k-1) : P[k-1]));\n                return link_cost(prev, curv);\n            };\n            int oldv=0,newv=0;\n            int idxs[4] = {i,i+1,j,j+1};\n            for(int x=0;x<4;x++){\n                int k=idxs[x];\n                bool dup=false;\n                for(int y=0;y<x;y++) if(idxs[y]==k) dup=true;\n                if(dup) continue;\n                oldv += contrib_at(k,false);\n                newv += contrib_at(k,true);\n            }\n            return newv-oldv;\n        };\n\n        auto delta_insert = [&](const vector<int>& P, int i, int j) -> int {\n            if (i == j) return 0;\n            int x = P[i];\n            if (i < j) {\n                int A = (i==0 ? -1 : P[i-1]);\n                int B = P[i+1];\n                int Y = P[j];\n                int Z = (j==M-1 ? -1 : P[j+1]);\n                int d=0;\n                d -= link_cost(A,x);\n                d -= link_cost(x,B);\n                d += link_cost(A,B);\n                if(Z!=-1){\n                    d -= link_cost(Y,Z);\n                    d += link_cost(Y,x);\n                    d += link_cost(x,Z);\n                } else d += link_cost(Y,x);\n                return d;\n            } else {\n                int A = (j==0 ? -1 : P[j-1]);\n                int B = P[j];\n                int C = P[i-1];\n                int D = (i==M-1 ? -1 : P[i+1]);\n                int d=0;\n                d -= link_cost(A,B);\n                d += link_cost(A,x);\n                d += link_cost(x,B);\n                d -= link_cost(C,x);\n                if(D!=-1){\n                    d -= link_cost(x,D);\n                    d += link_cost(C,D);\n                }\n                return d;\n            }\n        };\n\n        auto delta_block = [&](const vector<int>& P, int l, int r, int p) -> int {\n            if (l > r) swap(l,r);\n            if (p >= l && p <= r+1) return 0;\n            int A = (l==0 ? -1 : P[l-1]);\n            int B = P[l];\n            int C = P[r];\n            int D = (r==M-1 ? -1 : P[r+1]);\n            int E,F;\n            if (p==0) { E=-1; F=P[0]; }\n            else if (p==M) { E=P[M-1]; F=-1; }\n            else { E=P[p-1]; F=P[p]; }\n            int oldv = link_cost(A,B) + link_cost(C,D) + link_cost(E,F);\n            int newv = link_cost(A,D) + link_cost(E,B) + link_cost(C,F);\n            return newv-oldv;\n        };\n\n        vector<Candidate> pool;\n        while (now_sec() < endTime) {\n            vector<int> P = (ur(rng) < 0.60 ? greedy_init() : random_init());\n            int curCost = eval_perm(P);\n            int bestLocal = curCost;\n            vector<int> bestP = P;\n\n            double sliceStart = now_sec();\n            double sliceEnd = min(endTime, sliceStart + 0.18);\n            const double Tbegin = 28.0, Tend = 0.35;\n\n            while (now_sec() < sliceEnd) {\n                double prog = (now_sec()-sliceStart) / max(1e-9, (sliceEnd-sliceStart));\n                double temp = Tbegin * pow(Tend / Tbegin, prog);\n\n                double r = ur(rng);\n                int d = 0;\n\n                if (r < 0.55) {\n                    int i = (int)(ur(rng) * M);\n                    int j = (int)(ur(rng) * M);\n                    while (j == i) j = (int)(ur(rng) * M);\n                    d = delta_swap(P, i, j);\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) { swap(P[i], P[j]); curCost += d; }\n                } else if (r < 0.85) {\n                    int i = (int)(ur(rng) * M);\n                    int j = (int)(ur(rng) * M);\n                    while (j == i) j = (int)(ur(rng) * M);\n                    d = delta_insert(P, i, j);\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                        if (i < j) rotate(P.begin()+i, P.begin()+i+1, P.begin()+j+1);\n                        else       rotate(P.begin()+j, P.begin()+i,   P.begin()+i+1);\n                        curCost += d;\n                    }\n                } else {\n                    int l = (int)(ur(rng) * M);\n                    int r2 = (int)(ur(rng) * M);\n                    if (l > r2) swap(l, r2);\n                    if (l == r2) continue;\n                    int p = (int)(ur(rng) * (M+1));\n                    if (p >= l && p <= r2+1) continue;\n                    d = delta_block(P, l, r2, p);\n                    if (d == 0) continue;\n                    if (d <= 0 || ur(rng) < exp(-(double)d / temp)) {\n                        if (p < l) rotate(P.begin()+p, P.begin()+l,   P.begin()+r2+1);\n                        else       rotate(P.begin()+l, P.begin()+r2+1, P.begin()+p);\n                        curCost += d;\n                    }\n                }\n\n                if (curCost < bestLocal) { bestLocal = curCost; bestP = P; }\n            }\n\n            add_pool(pool, poolK, bestLocal, bestP);\n        }\n        sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b){ return a.approx < b.approx; });\n        return pool;\n    };\n\n    // ---- Time plan ----\n    double t0 = now_sec();\n    double TIME_END = t0 + 1.93;\n\n    double t_sa1_end = t0 + 1.00; // cap4\n    double t_sa2_end = t0 + 1.52; // cap2\n\n    vector<Candidate> poolAll;\n    {\n        auto p4 = run_SA(edge4, t_sa1_end, 36);\n        for (auto &c : p4) poolAll.push_back(move(c));\n        auto p2 = run_SA(edge2, t_sa2_end, 36);\n        for (auto &c : p2) poolAll.push_back(move(c));\n    }\n    if (poolAll.empty()) {\n        vector<int> P(M); iota(P.begin(), P.end(), 0);\n        poolAll.push_back({0, P, hash_perm(P)});\n    }\n\n    sort(poolAll.begin(), poolAll.end(), [](const Candidate& a, const Candidate& b){ return a.approx < b.approx; });\n    vector<Candidate> uniq;\n    {\n        unordered_set<uint64_t> seen;\n        for (auto &c : poolAll) {\n            if (seen.insert(c.h).second) uniq.push_back(move(c));\n            if ((int)uniq.size() >= 85) break;\n        }\n    }\n\n    // deterministic seed base for CAP_HASH\n    uint64_t seedBase = splitmix64((uint64_t)startCell * 1000003ULL ^ (uint64_t)(si + 17) * 10007ULL ^ (uint64_t)(sj + 23));\n    for (int id = 0; id < V; id++) seedBase ^= splitmix64((uint64_t)letterAtCell[id] * 1315423911ULL + (uint64_t)id);\n\n    vector<Policy> policies = {\n        {Policy::MINCOST_DET, 0, 0},\n        {Policy::CAP_DET, 4, 0},\n        {Policy::CAP_DET, 2, 0},\n        {Policy::CAP_DET, 1, 0},\n        {Policy::CAP_HASH, 4, seedBase},\n        {Policy::CAP_HASH, 4, seedBase ^ 0x9e3779b97f4a7c15ULL},\n        {Policy::CAP_HASH, 2, seedBase ^ 0x243f6a8885a308d3ULL},\n    };\n\n    // ---- Exact evaluation: pick best (perm, policy) ----\n    int bestExact = INT_MAX;\n    vector<int> bestPerm;\n    Policy bestPol{Policy::CAP_DET, 4, 0};\n\n    double t_eval_end = TIME_END - 0.30;\n    for (auto &cand : uniq) {\n        for (auto pol : policies) {\n            build_S_to(cand.perm, pol, Sbuf);\n            int ec = exact_cost_string(Sbuf);\n            if (ec < bestExact) { bestExact = ec; bestPerm = cand.perm; bestPol = pol; }\n            if (now_sec() > t_eval_end) break;\n        }\n        if (now_sec() > t_eval_end) break;\n    }\n\n    // ---- Exact improving-only hill-climb on permutation ----\n    const vector<vector<int>>* edgeFilterPtr = nullptr;\n    if (bestPol.type == Policy::CAP_HASH || bestPol.type == Policy::MINCOST_DET) edgeFilterPtr = &edgeMin;\n    else if (bestPol.cap == 4) edgeFilterPtr = &edge4;\n    else if (bestPol.cap == 2) edgeFilterPtr = &edge2;\n    else edgeFilterPtr = &edge1;\n    const auto &edgeFilter = *edgeFilterPtr;\n\n    auto link_cost_f = [&](int prev, int nxt) -> int {\n        if (nxt < 0) return 0;\n        if (prev < 0) return startCostWord[nxt];\n        return edgeFilter[prev][nxt];\n    };\n\n    auto delta_swap_f = [&](const vector<int>& P, int i, int j) -> int {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n        int a = P[i], b = P[j];\n        auto get = [&](int k)->int{ if(k==i) return b; if(k==j) return a; return P[k]; };\n        auto contrib_at = [&](int k, bool after)->int{\n            if (k<0||k>=M) return 0;\n            int curv = after ? get(k) : P[k];\n            int prev = (k==0 ? -1 : (after ? get(k-1) : P[k-1]));\n            return link_cost_f(prev, curv);\n        };\n        int oldv=0,newv=0;\n        int idxs[4] = {i,i+1,j,j+1};\n        for(int x=0;x<4;x++){\n            int k=idxs[x];\n            bool dup=false;\n            for(int y=0;y<x;y++) if(idxs[y]==k) dup=true;\n            if(dup) continue;\n            oldv += contrib_at(k,false);\n            newv += contrib_at(k,true);\n        }\n        return newv-oldv;\n    };\n\n    auto delta_insert_f = [&](const vector<int>& P, int i, int j) -> int {\n        if (i == j) return 0;\n        int x = P[i];\n        if (i < j) {\n            int A = (i==0 ? -1 : P[i-1]);\n            int B = P[i+1];\n            int Y = P[j];\n            int Z = (j==M-1 ? -1 : P[j+1]);\n            int d=0;\n            d -= link_cost_f(A,x);\n            d -= link_cost_f(x,B);\n            d += link_cost_f(A,B);\n            if(Z!=-1){\n                d -= link_cost_f(Y,Z);\n                d += link_cost_f(Y,x);\n                d += link_cost_f(x,Z);\n            } else d += link_cost_f(Y,x);\n            return d;\n        } else {\n            int A = (j==0 ? -1 : P[j-1]);\n            int B = P[j];\n            int C = P[i-1];\n            int D = (i==M-1 ? -1 : P[i+1]);\n            int d=0;\n            d -= link_cost_f(A,B);\n            d += link_cost_f(A,x);\n            d += link_cost_f(x,B);\n            d -= link_cost_f(C,x);\n            if(D!=-1){\n                d -= link_cost_f(x,D);\n                d += link_cost_f(C,D);\n            }\n            return d;\n        }\n    };\n\n    auto delta_block_f = [&](const vector<int>& P, int l, int r, int p) -> int {\n        if (l > r) swap(l,r);\n        if (p >= l && p <= r+1) return 0;\n        int A = (l==0 ? -1 : P[l-1]);\n        int B = P[l];\n        int C = P[r];\n        int D = (r==M-1 ? -1 : P[r+1]);\n        int E,F;\n        if (p==0) { E=-1; F=P[0]; }\n        else if (p==M) { E=P[M-1]; F=-1; }\n        else { E=P[p-1]; F=P[p]; }\n        int oldv = link_cost_f(A,B) + link_cost_f(C,D) + link_cost_f(E,F);\n        int newv = link_cost_f(A,D) + link_cost_f(E,B) + link_cost_f(C,F);\n        return newv-oldv;\n    };\n\n    vector<int> curPerm = bestPerm;\n    int curExact = bestExact;\n\n    double t_hill_end = TIME_END - 0.08;\n    while (now_sec() < t_hill_end) {\n        int type = (int)(ur(rng) * 3.0); // 0 swap, 1 insert, 2 block\n        vector<int> backup;\n        int i=-1,j=-1,l=-1,r=-1,p=-1;\n        int approxDelta = 0;\n\n        if (type == 0) {\n            i = (int)(ur(rng) * M);\n            j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            approxDelta = delta_swap_f(curPerm, i, j);\n            if (approxDelta > 90) continue;\n            if (approxDelta > 0 && ur(rng) < 0.80) continue;\n            swap(curPerm[i], curPerm[j]);\n        } else if (type == 1) {\n            i = (int)(ur(rng) * M);\n            j = (int)(ur(rng) * M);\n            while (j == i) j = (int)(ur(rng) * M);\n            approxDelta = delta_insert_f(curPerm, i, j);\n            if (approxDelta > 90) continue;\n            if (approxDelta > 0 && ur(rng) < 0.80) continue;\n            if (i < j) rotate(curPerm.begin()+i, curPerm.begin()+i+1, curPerm.begin()+j+1);\n            else       rotate(curPerm.begin()+j, curPerm.begin()+i,   curPerm.begin()+i+1);\n        } else {\n            l = (int)(ur(rng) * M);\n            r = (int)(ur(rng) * M);\n            if (l > r) swap(l, r);\n            if (l == r) continue;\n            p = (int)(ur(rng) * (M+1));\n            if (p >= l && p <= r+1) continue;\n            approxDelta = delta_block_f(curPerm, l, r, p);\n            if (approxDelta > 140) continue;\n            if (approxDelta > 0 && ur(rng) < 0.85) continue;\n            backup = curPerm;\n            if (p < l) rotate(curPerm.begin()+p, curPerm.begin()+l,   curPerm.begin()+r+1);\n            else       rotate(curPerm.begin()+l, curPerm.begin()+r+1, curPerm.begin()+p);\n        }\n\n        build_S_to(curPerm, bestPol, Sbuf);\n        int ec = exact_cost_string(Sbuf);\n\n        if (ec < curExact) {\n            curExact = ec;\n            if (ec < bestExact) {\n                bestExact = ec;\n                bestPerm = curPerm;\n            }\n        } else {\n            // revert\n            if (type == 0) swap(curPerm[i], curPerm[j]);\n            else if (type == 1) {\n                if (i < j) rotate(curPerm.begin()+i, curPerm.begin()+j,   curPerm.begin()+j+1);\n                else       rotate(curPerm.begin()+j, curPerm.begin()+j+1, curPerm.begin()+i+1);\n            } else {\n                curPerm.swap(backup);\n            }\n        }\n    }\n\n    // Final policy re-check for the final permutation (cheap)\n    curPerm = bestPerm;\n    for (auto pol : policies) {\n        build_S_to(curPerm, pol, Sbuf);\n        int ec = exact_cost_string(Sbuf);\n        if (ec < bestExact) {\n            bestExact = ec;\n            bestPol = pol;\n        }\n    }\n\n    // Output final exact optimal coordinate path\n    build_S_to(bestPerm, bestPol, Sbuf);\n    auto [finalCost, pathCells] = exact_path_string(Sbuf);\n    for (int cell : pathCells) {\n        cout << (cell / N) << ' ' << (cell % N) << \"\\n\";\n    }\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    double limit;\n    Timer(double limitSec=2.85) : st(chrono::high_resolution_clock::now()), limit(limitSec) {}\n    double elapsed() const {\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - st).count();\n    }\n    bool over() const { return elapsed() >= limit; }\n};\n\nstruct Query {\n    vector<uint64_t> bits;\n    int k;\n    double y;\n    double w;\n    double base;\n    double alpha;\n    bool exact;\n};\n\nstruct Placement {\n    int di, dj;\n    vector<uint64_t> bits;\n    vector<int16_t> inter;\n    vector<int> neigh;\n};\n\nstruct Field {\n    vector<Placement> ps;\n    int area = 0;\n};\n\nstruct Solution {\n    vector<int> idx;\n    double cost;\n};\n\nstruct Solver {\n    int N, M;\n    double eps;\n    int N2, L;\n    int op_limit;\n    int ops = 0;\n\n    vector<Field> fields;\n    vector<Query> queries;\n    unordered_map<uint64_t, int> qhash2id;\n\n    vector<int> drilledVal;\n    int drilledCnt = 0;\n\n    vector<vector<int>> validList;\n    vector<vector<unsigned char>> validFlag;\n\n    mt19937 rng;\n    Timer timer;\n\n    Solver(int N_, int M_, double eps_) : N(N_), M(M_), eps(eps_), timer(2.85) {\n        N2 = N * N;\n        L = (N2 + 63) / 64;\n        op_limit = 2 * N2;\n        drilledVal.assign(N2, -1);\n    }\n\n    // ---- I/O ----\n    void out_flush(const string& s) { cout << s << '\\n' << flush; }\n\n    int drillCell(int i, int j) {\n        out_flush(\"q 1 \" + to_string(i) + \" \" + to_string(j));\n        ops++;\n        int v;\n        if (!(cin >> v)) exit(0);\n        return v;\n    }\n\n    int divineCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        string s;\n        s.reserve(10 + d * 8);\n        s += \"q \" + to_string(d);\n        for (auto &p: ps) s += \" \" + to_string(p.first) + \" \" + to_string(p.second);\n        out_flush(s);\n        ops++;\n        int y;\n        if (!(cin >> y)) exit(0);\n        return y;\n    }\n\n    int answerCells(const vector<pair<int,int>>& ps) {\n        int d = (int)ps.size();\n        string s;\n        s.reserve(10 + d * 8);\n        s += \"a \" + to_string(d);\n        for (auto &p: ps) s += \" \" + to_string(p.first) + \" \" + to_string(p.second);\n        out_flush(s);\n        ops++;\n        int ok;\n        if (!(cin >> ok)) exit(0);\n        return ok;\n    }\n\n    // preserve ability to drill-all + final answer\n    bool canSpendOps(int extra) const {\n        int remainingToDrill = N2 - drilledCnt;\n        return ops + extra + remainingToDrill + 1 <= op_limit;\n    }\n\n    // ---- bit helpers ----\n    inline void bitSet(vector<uint64_t>& b, int idx) const { b[idx >> 6] |= 1ULL << (idx & 63); }\n    inline bool bitGet(const vector<uint64_t>& b, int idx) const { return (b[idx >> 6] >> (idx & 63)) & 1ULL; }\n\n    int popcountAnd(const vector<uint64_t>& a, const vector<uint64_t>& b) const {\n        int s = 0;\n        for (int t = 0; t < L; t++) s += __builtin_popcountll(a[t] & b[t]);\n        return s;\n    }\n\n    vector<uint64_t> bitsFromCells(const vector<int>& v) const {\n        vector<uint64_t> b(L, 0ULL);\n        for (int idx: v) bitSet(b, idx);\n        return b;\n    }\n\n    uint64_t hashBits(const vector<uint64_t>& b) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int t = 0; t < (int)b.size(); t++) {\n            h = splitmix64(h ^ splitmix64(b[t] + 0x9e3779b97f4a7c15ULL + (uint64_t)t));\n        }\n        return h;\n    }\n\n    // ---- deterministic RNG seed ----\n    void seedRNG(const vector<vector<pair<int,int>>>& shapes) {\n        uint64_t h = 0x123456789abcdef0ULL;\n        h = splitmix64(h ^ (uint64_t)N);\n        h = splitmix64(h ^ ((uint64_t)M << 32));\n        h = splitmix64(h ^ (uint64_t)llround(eps * 100000.0)); // eps with precision\n        for (int k = 0; k < M; k++) {\n            h = splitmix64(h ^ (uint64_t)shapes[k].size() * 0x9e3779b97f4a7c15ULL);\n            for (auto [i,j] : shapes[k]) {\n                uint64_t x = (uint64_t)i * 1315423911ULL + (uint64_t)j * 2654435761ULL + (uint64_t)k * 97531ULL;\n                h = splitmix64(h ^ x);\n            }\n        }\n        uint32_t s1 = (uint32_t)h;\n        uint32_t s2 = (uint32_t)(h >> 32);\n        seed_seq seq{ s1, s2, 0xdeadbeefU, 0x12345678U };\n        rng.seed(seq);\n    }\n\n    // ---- placements ----\n    void buildPlacements(const vector<vector<pair<int,int>>>& shapes) {\n        seedRNG(shapes);\n\n        fields.resize(M);\n        validList.assign(M, {});\n        validFlag.assign(M, {});\n        for (int f = 0; f < M; f++) {\n            const auto& shp = shapes[f];\n            fields[f].area = (int)shp.size();\n\n            int maxI = 0, maxJ = 0;\n            for (auto [x,y]: shp) { maxI = max(maxI, x); maxJ = max(maxJ, y); }\n            int diMax = N - maxI - 1;\n            int djMax = N - maxJ - 1;\n\n            vector<vector<int>> mp(diMax+1, vector<int>(djMax+1, -1));\n            for (int di = 0; di <= diMax; di++) for (int dj = 0; dj <= djMax; dj++) {\n                Placement p;\n                p.di = di; p.dj = dj;\n                p.bits.assign(L, 0ULL);\n                for (auto [x,y]: shp) {\n                    int i = di + x, j = dj + y;\n                    int idx = i*N + j;\n                    bitSet(p.bits, idx);\n                }\n                fields[f].ps.push_back(std::move(p));\n                mp[di][dj] = (int)fields[f].ps.size()-1;\n            }\n\n            for (auto &p: fields[f].ps) {\n                int di = p.di, dj = p.dj;\n                static int dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n                for (auto &d: dd) {\n                    int ndi = di + d[0], ndj = dj + d[1];\n                    if (0 <= ndi && ndi <= diMax && 0 <= ndj && ndj <= djMax) {\n                        int ni = mp[ndi][ndj];\n                        if (ni >= 0) p.neigh.push_back(ni);\n                    }\n                }\n            }\n\n            int sz = (int)fields[f].ps.size();\n            validList[f].resize(sz);\n            iota(validList[f].begin(), validList[f].end(), 0);\n            validFlag[f].assign(sz, 1);\n        }\n    }\n\n    // ---- queries ----\n    int addOrMergeQuery(const vector<uint64_t>& bits, int k, double y, bool exact) {\n        Query nq;\n        nq.bits = bits;\n        nq.k = k;\n        nq.y = y;\n        nq.exact = exact;\n\n        if (exact) {\n            nq.base = 0.0;\n            nq.alpha = 1.0;\n            nq.w = 1e6;\n        } else {\n            nq.base = (double)k * eps;\n            nq.alpha = 1.0 - 2.0 * eps;\n            double var = (double)k * eps * (1.0 - eps) + 0.25;\n            nq.w = 1.0 / (var + 1e-6);\n        }\n\n        uint64_t h = hashBits(bits);\n        auto it = qhash2id.find(h);\n        if (it != qhash2id.end()) {\n            int id = it->second;\n            Query &q = queries[id];\n            double wsum = q.w + nq.w;\n            q.y = (q.y * q.w + nq.y * nq.w) / wsum;\n            q.w = wsum;\n            q.exact = q.exact || nq.exact;\n            return id;\n        }\n\n        int qid = (int)queries.size();\n        qhash2id[h] = qid;\n        queries.push_back(std::move(nq));\n\n        for (int f = 0; f < M; f++) {\n            for (auto &p: fields[f].ps) {\n                int c = popcountAnd(p.bits, queries[qid].bits);\n                p.inter.push_back((int16_t)c);\n            }\n        }\n        return qid;\n    }\n\n    bool normalizeCells(vector<int>& v) const {\n        for (int x : v) if (x < 0 || x >= N2) return false;\n        sort(v.begin(), v.end());\n        v.erase(unique(v.begin(), v.end()), v.end());\n        return true;\n    }\n\n    int doDivination(vector<int> cellIdx) {\n        if (!canSpendOps(1)) return -1;\n        if (!normalizeCells(cellIdx)) return -1;\n        if ((int)cellIdx.size() < 2) return -1;\n\n        vector<pair<int,int>> out;\n        out.reserve(cellIdx.size());\n        for (int idx: cellIdx) out.push_back({idx / N, idx % N});\n        int y = divineCells(out);\n\n        auto bits = bitsFromCells(cellIdx);\n        return addOrMergeQuery(bits, (int)cellIdx.size(), (double)y, false);\n    }\n\n    void pruneByZeroCell(int idx) {\n        for (int f = 0; f < M; f++) {\n            vector<int> nv;\n            nv.reserve(validList[f].size());\n            for (int pi : validList[f]) {\n                if (!bitGet(fields[f].ps[pi].bits, idx)) nv.push_back(pi);\n                else validFlag[f][pi] = 0;\n            }\n            if (!nv.empty()) validList[f].swap(nv);\n        }\n    }\n\n    void doDrill(int idx) {\n        if (drilledVal[idx] != -1) return;\n        if (!canSpendOps(1)) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<uint64_t> bits(L, 0ULL);\n        bitSet(bits, idx);\n        addOrMergeQuery(bits, 1, (double)v, true);\n\n        if (v == 0) pruneByZeroCell(idx);\n    }\n\n    void doDrillForce(int idx) { // fallback only\n        if (drilledVal[idx] != -1) return;\n        if (ops >= op_limit - 1) return;\n\n        int i = idx / N, j = idx % N;\n        int v = drillCell(i, j);\n        drilledVal[idx] = v;\n        drilledCnt++;\n\n        vector<uint64_t> bits(L, 0ULL);\n        bitSet(bits, idx);\n        addOrMergeQuery(bits, 1, (double)v, true);\n\n        if (v == 0) pruneByZeroCell(idx);\n    }\n\n    // ---- query constructors ----\n    vector<int> allCells() const { vector<int> v(N2); iota(v.begin(), v.end(), 0); return v; }\n    vector<int> cellsRow(int r) const { vector<int> v; v.reserve(N); for(int c=0;c<N;c++) v.push_back(r*N+c); return v; }\n    vector<int> cellsCol(int c) const { vector<int> v; v.reserve(N); for(int r=0;r<N;r++) v.push_back(r*N+c); return v; }\n    vector<int> cellsBlock(int r0,int r1,int c0,int c1) const {\n        vector<int> v;\n        for(int r=r0;r<r1;r++) for(int c=c0;c<c1;c++) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> cellsChecker(int parity) const {\n        vector<int> v;\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++) if(((r+c)&1)==parity) v.push_back(r*N+c);\n        return v;\n    }\n    vector<int> randomKCells(int k) {\n        k = max(2, min(k, N2));\n        vector<int> v(N2);\n        iota(v.begin(), v.end(), 0);\n        shuffle(v.begin(), v.end(), rng);\n        v.resize(k);\n        return v;\n    }\n\n    // ---- greedy init ----\n    vector<int> greedyInit() {\n        int Q = (int)queries.size();\n        vector<double> err(Q);\n        for (int q = 0; q < Q; q++) err[q] = queries[q].base - queries[q].y;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b){ return fields[a].area > fields[b].area; });\n\n        vector<int> idx(M, 0);\n        for (int f : order) {\n            int bestP = validList[f][0];\n            double bestDelta = 1e100;\n            for (int p : validList[f]) {\n                double delta = 0.0;\n                auto &pl = fields[f].ps[p];\n                for (int q = 0; q < Q; q++) {\n                    int c = (int)pl.inter[q];\n                    if (!c) continue;\n                    double d = queries[q].alpha * (double)c;\n                    delta += queries[q].w * (2.0 * err[q] * d + d * d);\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestP = p;\n                }\n            }\n            idx[f] = bestP;\n            auto &pl = fields[f].ps[bestP];\n            for (int q = 0; q < Q; q++) {\n                int c = (int)pl.inter[q];\n                if (!c) continue;\n                err[q] += queries[q].alpha * (double)c;\n            }\n        }\n        return idx;\n    }\n\n    // ---- SA ----\n    Solution runSA(const vector<int>& startIdx, int iters) {\n        int Q = (int)queries.size();\n        vector<int> idx = startIdx;\n\n        vector<double> err(Q);\n        for (int q = 0; q < Q; q++) err[q] = queries[q].base - queries[q].y;\n        for (int f = 0; f < M; f++) {\n            auto &pl = fields[f].ps[idx[f]];\n            for (int q = 0; q < Q; q++) {\n                int c = (int)pl.inter[q];\n                if (!c) continue;\n                err[q] += queries[q].alpha * (double)c;\n            }\n        }\n        double cost = 0;\n        for (int q = 0; q < Q; q++) cost += queries[q].w * err[q] * err[q];\n\n        vector<int> bestIdx = idx;\n        double bestCost = cost;\n\n        double T0 = 1.10, T1 = 0.03;\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        uniform_int_distribution<int> fieldDist(0, M-1);\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 255) == 0 && timer.over()) break;\n            double tt = (double)it / max(1, iters - 1);\n            double T = T0 * pow(T1 / T0, tt);\n\n            int f = fieldDist(rng);\n            int cur = idx[f];\n            int nxt = cur;\n\n            auto &ps = fields[f].ps;\n            bool proposed = false;\n            if (!ps[cur].neigh.empty() && ur(rng) < 0.70) {\n                uniform_int_distribution<int> nd(0, (int)ps[cur].neigh.size() - 1);\n                int cand = ps[cur].neigh[nd(rng)];\n                if (validFlag[f][cand]) { nxt = cand; proposed = true; }\n            }\n            if (!proposed) {\n                auto &vl = validList[f];\n                uniform_int_distribution<int> vd(0, (int)vl.size() - 1);\n                nxt = vl[vd(rng)];\n            }\n            if (nxt == cur) continue;\n\n            auto &oldP = ps[cur];\n            auto &newP = ps[nxt];\n\n            double delta = 0.0;\n            for (int q = 0; q < Q; q++) {\n                int dd = (int)newP.inter[q] - (int)oldP.inter[q];\n                if (!dd) continue;\n                double d = queries[q].alpha * (double)dd;\n                delta += queries[q].w * (2.0 * err[q] * d + d * d);\n            }\n\n            if (delta <= 0.0 || ur(rng) < exp(-delta / T)) {\n                for (int q = 0; q < Q; q++) {\n                    int dd = (int)newP.inter[q] - (int)oldP.inter[q];\n                    if (!dd) continue;\n                    err[q] += queries[q].alpha * (double)dd;\n                }\n                idx[f] = nxt;\n                cost += delta;\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestIdx = idx;\n                }\n            }\n        }\n        return Solution{bestIdx, bestCost};\n    }\n\n    vector<Solution> sampleSolutions(int wantK, int restarts, int iters) {\n        vector<Solution> sols;\n        sols.reserve(restarts);\n\n        vector<int> base = greedyInit();\n        sols.push_back(runSA(base, iters));\n\n        for (int r = 1; r < restarts; r++) {\n            if (timer.over()) break;\n            vector<int> st = base;\n            for (int t = 0; t < 2; t++) {\n                int f = (int)(rng() % M);\n                auto &vl = validList[f];\n                st[f] = vl[rng() % vl.size()];\n            }\n            sols.push_back(runSA(st, iters));\n        }\n\n        sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b){ return a.cost < b.cost; });\n\n        unordered_set<uint64_t> seen;\n        vector<Solution> out;\n        out.reserve(wantK);\n        for (auto &s: sols) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int x: s.idx) h = splitmix64(h ^ ((uint64_t)x + 0x9e3779b97f4a7c15ULL));\n            if (seen.insert(h).second) out.push_back(s);\n            if ((int)out.size() >= wantK) break;\n        }\n        if (out.empty()) out.push_back(sols[0]);\n        return out;\n    }\n\n    // ---- unions ----\n    vector<uint64_t> unionBits(const Solution& s) const {\n        vector<uint64_t> uni(L, 0ULL);\n        for (int f = 0; f < M; f++) {\n            auto &b = fields[f].ps[s.idx[f]].bits;\n            for (int t = 0; t < L; t++) uni[t] |= b[t];\n        }\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] > 0) uni[idx>>6] |= (1ULL << (idx&63));\n            else if (drilledVal[idx] == 0) uni[idx>>6] &= ~(1ULL << (idx&63));\n        }\n        return uni;\n    }\n\n    uint64_t hashUnion(const vector<uint64_t>& uni) const {\n        uint64_t h = 1469598103934665603ULL;\n        for (int t = 0; t < L; t++) h = splitmix64(h ^ splitmix64(uni[t] + 0x123456789abcdef0ULL + (uint64_t)t));\n        return h;\n    }\n\n    vector<pair<int,int>> answerFromUnionBits(const vector<uint64_t>& uni) const {\n        vector<pair<int,int>> ans;\n        ans.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) if ((uni[idx>>6] >> (idx&63)) & 1ULL) ans.push_back({idx / N, idx % N});\n        return ans;\n    }\n\n    pair<vector<double>, vector<int>> unionProbAndUncertain(const vector<Solution>& sols) const {\n        vector<int> cnt(N2, 0);\n        for (auto &s: sols) {\n            auto uni = unionBits(s);\n            for (int idx = 0; idx < N2; idx++) if ((uni[idx>>6] >> (idx&63)) & 1ULL) cnt[idx]++;\n        }\n        vector<double> p(N2, 0.0);\n        vector<int> uncertain;\n        uncertain.reserve(N2);\n        int K = (int)sols.size();\n        for (int idx = 0; idx < N2; idx++) {\n            if (drilledVal[idx] != -1) {\n                p[idx] = (drilledVal[idx] > 0) ? 1.0 : 0.0;\n                continue;\n            }\n            p[idx] = (double)cnt[idx] / max(1, K);\n            if (p[idx] > 0.0 && p[idx] < 1.0) uncertain.push_back(idx);\n        }\n        return {p, uncertain};\n    }\n\n    // ---- informative mask ----\n    vector<int> chooseInformativeMask(const vector<Solution>& sols, const vector<int>& focus, const vector<int>& pickSolIdx) {\n        int kTarget = (int)llround((double)N2 * 0.60);\n        kTarget = max(2, min(kTarget, N2));\n        int tries = 16;\n\n        vector<int> all(N2);\n        iota(all.begin(), all.end(), 0);\n\n        auto noiseVar = [&](int k)->double {\n            return (double)k * eps * (1.0 - eps) + 0.25;\n        };\n\n        uniform_real_distribution<double> ur(0.0, 1.0);\n        vector<unsigned char> mark(N2);\n\n        double bestScore = -1e100;\n        vector<int> bestMask;\n\n        for (int t = 0; t < tries; t++) {\n            if (timer.over()) break;\n            fill(mark.begin(), mark.end(), 0);\n\n            vector<int> mask;\n            mask.reserve(kTarget);\n\n            for (int idx : focus) {\n                if ((int)mask.size() >= kTarget) break;\n                if (drilledVal[idx] != -1) continue;\n                if (!mark[idx] && ur(rng) < 0.72) {\n                    mark[idx] = 1;\n                    mask.push_back(idx);\n                }\n            }\n            shuffle(all.begin(), all.end(), rng);\n            for (int x : all) {\n                if ((int)mask.size() >= kTarget) break;\n                if (!mark[x]) {\n                    mark[x] = 1;\n                    mask.push_back(x);\n                }\n            }\n            if ((int)mask.size() < 2) continue;\n\n            auto bits = bitsFromCells(mask);\n            int k = (int)mask.size();\n\n            vector<double> pred;\n            pred.reserve(pickSolIdx.size());\n            for (int si : pickSolIdx) {\n                const auto &s = sols[si];\n                int sum = 0;\n                for (int f = 0; f < M; f++) sum += popcountAnd(fields[f].ps[s.idx[f]].bits, bits);\n                pred.push_back((double)k * eps + (1.0 - 2.0 * eps) * (double)sum);\n            }\n            double mean = 0;\n            for (double v : pred) mean += v;\n            mean /= max(1, (int)pred.size());\n            double var = 0;\n            for (double v : pred) { double d = v - mean; var += d * d; }\n            var /= max(1, (int)pred.size());\n\n            double score = (var / noiseVar(k)) * sqrt((double)k);\n            if (score > bestScore) {\n                bestScore = score;\n                bestMask = std::move(mask);\n            }\n        }\n\n        if (bestMask.empty()) bestMask = randomKCells(max(2, N2/2));\n        return bestMask;\n    }\n\n    // ---- initial queries ----\n    void initialDivinations() {\n        doDivination(allCells());\n        for (int i = 0; i < N; i++) doDivination(cellsRow(i));\n        for (int j = 0; j < N; j++) doDivination(cellsCol(j));\n\n        int B = (N >= 18) ? 4 : 3;\n        int step = (N + B - 1) / B;\n        for (int bi = 0; bi < B; bi++) for (int bj = 0; bj < B; bj++) {\n            int r0 = bi * step, r1 = min(N, (bi + 1) * step);\n            int c0 = bj * step, c1 = min(N, (bj + 1) * step);\n            auto v = cellsBlock(r0, r1, c0, c1);\n            if ((int)v.size() >= 2) doDivination(v);\n        }\n\n        doDivination(cellsChecker(0));\n        doDivination(cellsChecker(1));\n\n        int R0 = 65;\n        for (int t = 0; t < R0; t++) {\n            if (!canSpendOps(1)) break;\n            int k = (t & 1) ? (int)llround((double)N2 * 0.50) : (int)llround((double)N2 * 0.62);\n            doDivination(randomKCells(k));\n        }\n    }\n\n    // ---- fallback ----\n    void finalFallbackSolve() {\n        for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] == -1) doDrillForce(idx);\n\n        vector<pair<int,int>> oilCells;\n        oilCells.reserve(N2);\n        for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n\n        if (ops >= op_limit) return;\n        int ok = answerCells(oilCells);\n        if (ok == 1) return;\n\n        while (ops < op_limit) {\n            bool progressed = false;\n            for (int idx = 0; idx < N2 && ops < op_limit - 1; idx++) {\n                if (drilledVal[idx] == -1) { doDrillForce(idx); progressed = true; }\n            }\n            if (ops >= op_limit) break;\n            oilCells.clear();\n            for (int idx = 0; idx < N2; idx++) if (drilledVal[idx] > 0) oilCells.push_back({idx / N, idx % N});\n            int ok2 = answerCells(oilCells);\n            if (ok2 == 1) return;\n            if (!progressed) break;\n        }\n    }\n\n    // Try many cluster unions cheaply before fallback (no extra divinations here).\n    bool finalTryAnswers(const vector<vector<uint64_t>>& unions, const vector<int>& repIdx, int& answerAttempts, int maxAnswerAttempts) {\n        int K = (int)repIdx.size();\n        int limit = min(K, 12);\n        for (int t = 0; t < limit && answerAttempts < maxAnswerAttempts; t++) {\n            if (!canSpendOps(1)) break;\n            auto ans = answerFromUnionBits(unions[repIdx[t]]);\n            int ok = answerCells(ans);\n            answerAttempts++;\n            if (ok == 1) return true;\n        }\n        return false;\n    }\n\n    void solve() {\n        initialDivinations();\n\n        int drillsUsed = 0;\n        int answerAttempts = 0;\n        int maxAnswerAttempts = 28;\n\n        for (int phase = 0; phase < 18; phase++) { // slightly fewer phases, reserve time for final stage\n            if (timer.over()) break;\n\n            int Q = (int)queries.size();\n            int iters = min(11000, 3800 + 10 * Q);\n            int restarts = (eps >= 0.15 ? 24 : 20);\n            int wantK = 90;\n\n            auto sols = sampleSolutions(wantK, restarts, iters);\n            if (sols.empty()) break;\n\n            // cluster by union\n            struct Clu { uint64_t h; int cnt; int rep; double bestCost; };\n            unordered_map<uint64_t, int> id;\n            vector<Clu> clus;\n            vector<vector<uint64_t>> unions;\n            clus.reserve(sols.size());\n            unions.reserve(sols.size());\n\n            for (int i = 0; i < (int)sols.size(); i++) {\n                unions.push_back(unionBits(sols[i]));\n                uint64_t h = hashUnion(unions.back());\n                auto it = id.find(h);\n                if (it == id.end()) {\n                    int nid = (int)clus.size();\n                    id[h] = nid;\n                    clus.push_back(Clu{h, 1, i, sols[i].cost});\n                } else {\n                    int cid = it->second;\n                    clus[cid].cnt++;\n                    if (sols[i].cost < clus[cid].bestCost) {\n                        clus[cid].bestCost = sols[i].cost;\n                        clus[cid].rep = i;\n                    }\n                }\n            }\n            sort(clus.begin(), clus.end(), [](const Clu& a, const Clu& b){\n                if (a.cnt != b.cnt) return a.cnt > b.cnt;\n                return a.bestCost < b.bestCost;\n            });\n\n            auto [p, uncertain] = unionProbAndUncertain(sols);\n\n            // pick reps for informative masks\n            vector<int> pick;\n            {\n                int Kc = min(6, (int)clus.size());\n                for (int i = 0; i < Kc; i++) pick.push_back(clus[i].rep);\n                for (int i = 0; i < (int)sols.size() && (int)pick.size() < 18; i++) pick.push_back(i);\n                sort(pick.begin(), pick.end());\n                pick.erase(unique(pick.begin(), pick.end()), pick.end());\n                if (pick.size() < 2) { pick.clear(); pick.push_back(0); }\n            }\n\n            // diff focus\n            vector<int> focus = uncertain;\n            vector<int> diff;\n            if ((int)clus.size() >= 2) {\n                auto &u1 = unions[clus[0].rep];\n                auto &u2 = unions[clus[1].rep];\n                for (int idx = 0; idx < N2; idx++) {\n                    if (drilledVal[idx] != -1) continue;\n                    bool b1 = (u1[idx>>6] >> (idx&63)) & 1ULL;\n                    bool b2 = (u2[idx>>6] >> (idx&63)) & 1ULL;\n                    if (b1 != b2) diff.push_back(idx);\n                }\n                if (!diff.empty() && (int)diff.size() < (int)focus.size()) focus = diff;\n            }\n\n            int drillBudget = min(N2, (phase >= 9 ? 240 : 175));\n            int maxDrillUncertain = min(150, max(70, N2/3));\n            int diffAllThresh = min(200, max(80, N2/2));\n\n            // drill moderate diff\n            if (!diff.empty() && (int)diff.size() <= diffAllThresh && drillsUsed + (int)diff.size() <= drillBudget) {\n                for (int idx : diff) { doDrill(idx); drillsUsed++; }\n                continue;\n            }\n\n            // drill subset for large diff\n            if (!diff.empty() && drillsUsed < drillBudget && phase >= 2) {\n                vector<pair<double,int>> cand;\n                cand.reserve(diff.size());\n                for (int idx : diff) cand.push_back({abs(p[idx] - 0.5), idx});\n                sort(cand.begin(), cand.end());\n                int take = min({(phase < 6 ? 10 : 16), (int)cand.size(), drillBudget - drillsUsed});\n                if (take > 0) {\n                    for (int t = 0; t < take; t++) { doDrill(cand[t].second); drillsUsed++; }\n                    continue;\n                }\n            }\n\n            // answer policy\n            if (answerAttempts < maxAnswerAttempts && canSpendOps(1)) {\n                double dom = (double)clus[0].cnt / (double)max(1, (int)sols.size());\n                bool late = (phase >= 10 || drillsUsed >= 110 || timer.elapsed() > 2.55);\n\n                double baseThr = (eps <= 0.06 ? 0.55 : eps <= 0.12 ? 0.62 : 0.68);\n                double thr = baseThr - (late ? 0.10 : 0.0);\n                thr = max(0.45, thr); // don't go too low early\n\n                bool costGap = false;\n                if ((int)clus.size() >= 2) costGap = clus[1].bestCost > clus[0].bestCost * 1.10;\n\n                if (dom >= thr || costGap) {\n                    auto ans = answerFromUnionBits(unions[clus[0].rep]);\n                    int ok = answerCells(ans);\n                    answerAttempts++;\n                    if (ok == 1) return;\n                    if (canSpendOps(1)) doDivination(chooseInformativeMask(sols, focus, pick));\n                    continue;\n                }\n\n                // multi-candidate answering only when truly late AND not too diffuse\n                if (late && dom >= 0.25 && (int)clus.size() >= 2) {\n                    int tries = min(3, (int)clus.size());\n                    for (int t = 0; t < tries && answerAttempts < maxAnswerAttempts; t++) {\n                        if (!canSpendOps(1)) break;\n                        auto ans = answerFromUnionBits(unions[clus[t].rep]);\n                        int ok = answerCells(ans);\n                        answerAttempts++;\n                        if (ok == 1) return;\n                    }\n                    if (canSpendOps(1)) doDivination(chooseInformativeMask(sols, focus, pick));\n                    continue;\n                }\n            }\n\n            // drill uncertain if moderate\n            if ((int)uncertain.size() <= maxDrillUncertain && drillsUsed + (int)uncertain.size() <= drillBudget) {\n                for (int idx : uncertain) { doDrill(idx); drillsUsed++; }\n                continue;\n            }\n\n            // divinations\n            if (canSpendOps(1)) {\n                doDivination(chooseInformativeMask(sols, focus, pick));\n                if ((int)uncertain.size() > 160 && canSpendOps(1) && !timer.over())\n                    doDivination(chooseInformativeMask(sols, focus, pick));\n            } else break;\n        }\n\n        // Final attempt to avoid fallback: sample more and try many unions cheaply.\n        if (!timer.over() && answerAttempts < maxAnswerAttempts && canSpendOps(1)) {\n            int Q = (int)queries.size();\n            int iters = min(12000, 4200 + 10 * Q);\n            int restarts = (eps >= 0.15 ? 30 : 26);\n            int wantK = 140;\n\n            auto sols = sampleSolutions(wantK, restarts, iters);\n            if (!sols.empty()) {\n                struct Clu { uint64_t h; int cnt; int rep; double bestCost; };\n                unordered_map<uint64_t, int> id;\n                vector<Clu> clus;\n                vector<vector<uint64_t>> unions;\n                clus.reserve(sols.size());\n                unions.reserve(sols.size());\n\n                for (int i = 0; i < (int)sols.size(); i++) {\n                    unions.push_back(unionBits(sols[i]));\n                    uint64_t h = hashUnion(unions.back());\n                    auto it = id.find(h);\n                    if (it == id.end()) {\n                        int nid = (int)clus.size();\n                        id[h] = nid;\n                        clus.push_back(Clu{h, 1, i, sols[i].cost});\n                    } else {\n                        int cid = it->second;\n                        clus[cid].cnt++;\n                        if (sols[i].cost < clus[cid].bestCost) {\n                            clus[cid].bestCost = sols[i].cost;\n                            clus[cid].rep = i;\n                        }\n                    }\n                }\n                sort(clus.begin(), clus.end(), [](const Clu& a, const Clu& b){\n                    if (a.cnt != b.cnt) return a.cnt > b.cnt;\n                    return a.bestCost < b.bestCost;\n                });\n\n                vector<int> rep;\n                rep.reserve(clus.size());\n                for (auto &c : clus) rep.push_back(c.rep);\n                if (finalTryAnswers(unions, rep, answerAttempts, maxAnswerAttempts)) return;\n            }\n        }\n\n        finalFallbackSolve();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    double eps;\n    cin >> N >> M >> eps;\n\n    vector<vector<pair<int,int>>> shapes(M);\n    for (int k = 0; k < M; k++) {\n        int d; cin >> d;\n        shapes[k].resize(d);\n        for (int t = 0; t < d; t++) {\n            int i, j; cin >> i >> j;\n            shapes[k][t] = {i, j};\n        }\n    }\n\n    Solver solver(N, M, eps);\n    solver.buildPlacements(shapes);\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long NINF = -(1LL << 60);\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline void build_in_pref(const vector<int>& h, bitset<W+1>& in, vector<int>& pref) {\n    int N = (int)h.size();\n    pref.assign(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i + 1] = pref[i] + h[i];\n    in.reset();\n    for (int b = 1; b <= N - 1; b++) {\n        int y = pref[b];\n        if (1 <= y && y <= W - 1) in.set(y);\n    }\n}\n\nstatic inline bool dominates_need_arr(const int* sortedH, const vector<int>& need_sorted, int N) {\n    for (int i = 0; i < N; i++) if (sortedH[i] < need_sorted[i]) return false;\n    return true;\n}\n\n// Replace two values in a sorted array (length N): remove old0, old1, insert new0, new1.\nstatic inline void replace2_sorted(int* a, int N, int old0, int old1, int new0, int new1) {\n    int buf[55];\n    for (int i = 0; i < N; i++) buf[i] = a[i];\n    int len = N;\n\n    auto remove_one = [&](int v) {\n        int pos = (int)(lower_bound(buf, buf + len, v) - buf);\n        // assuming exists\n        if (pos == len || buf[pos] != v) {\n            // fallback linear\n            for (int i = 0; i < len; i++) if (buf[i] == v) { pos = i; break; }\n        }\n        for (int i = pos; i + 1 < len; i++) buf[i] = buf[i + 1];\n        len--;\n    };\n    auto insert_one = [&](int v) {\n        int pos = (int)(lower_bound(buf, buf + len, v) - buf);\n        for (int i = len; i > pos; i--) buf[i] = buf[i - 1];\n        buf[pos] = v;\n        len++;\n    };\n\n    remove_one(old0);\n    remove_one(old1);\n    insert_one(new0);\n    insert_one(new1);\n\n    for (int i = 0; i < N; i++) a[i] = buf[i];\n}\n\n// Infeasible day: minimize shortage penalty multiset by decrementing cheapest marginal units.\nstatic vector<int> multiset_infeasible_minpenalty(const vector<int>& a_sorted, const vector<int>& need_sorted) {\n    int N = (int)need_sorted.size();\n    vector<int> h = need_sorted;\n    int sumNeed = accumulate(h.begin(), h.end(), 0);\n    int T = sumNeed - W;\n\n    vector<int> firstCost(N);\n    for (int k = 0; k < N; k++) {\n        int r = a_sorted[k] % W;\n        int deltaArea = (r == 0 ? W : r);\n        firstCost[k] = 100 * deltaArea;\n    }\n\n    using P = pair<int,int>;\n    priority_queue<P, vector<P>, greater<P>> pq;\n    for (int k = 0; k < N; k++) if (h[k] > 1) pq.push({firstCost[k], k});\n\n    for (int t = 0; t < T; t++) {\n        auto [c, k] = pq.top(); pq.pop();\n        h[k]--;\n        if (h[k] > 1) pq.push({100000, k});\n    }\n\n    sort(h.begin(), h.end());\n    int sumH = accumulate(h.begin(), h.end(), 0);\n    h.back() += (W - sumH);\n    sort(h.begin(), h.end());\n    return h;\n}\n\n// Feasible-day DP (ordered lower bounds) maximizing boundary matches with neighbor boundary sets.\n// Objective: maximize sum 2000*w(y), tie-break: -|y-cur|.\nstatic vector<int> dp_feasible_setbased(const vector<int>& need,\n                                       const bitset<W+1>* prevIn,\n                                       const bitset<W+1>* nextIn,\n                                       const vector<int>& curPref) {\n    int N = (int)need.size();\n    vector<int> suf(N + 1, 0);\n    for (int i = N - 1; i >= 0; i--) suf[i] = suf[i + 1] + need[i];\n\n    static long long dp[W+1], ndp[W+1], bestVal[W+1];\n    static int bestIdx[W+1];\n    static int16_t par[55][W+1];\n\n    for (int p = 0; p <= W; p++) dp[p] = NINF;\n    dp[0] = 0;\n    for (int k = 0; k <= N; k++) for (int p = 0; p <= W; p++) par[k][p] = -1;\n\n    auto w_at = [&](int y)->int{\n        int w = 0;\n        if (prevIn && prevIn->test(y)) w++;\n        if (nextIn && nextIn->test(y)) w++;\n        return w;\n    };\n\n    for (int k = 0; k < N; k++) {\n        bestVal[0] = dp[0];\n        bestIdx[0] = 0;\n        for (int p = 1; p <= W; p++) {\n            if (dp[p] > bestVal[p - 1]) { bestVal[p] = dp[p]; bestIdx[p] = p; }\n            else { bestVal[p] = bestVal[p - 1]; bestIdx[p] = bestIdx[p - 1]; }\n        }\n\n        for (int p = 0; p <= W; p++) ndp[p] = NINF;\n\n        for (int p2 = 0; p2 <= W; p2++) {\n            if (W - p2 < suf[k + 1]) continue;\n            int lim = p2 - need[k];\n            if (lim < 0) continue;\n            long long base = bestVal[lim];\n            if (base <= NINF/4) continue;\n\n            long long add = 0;\n            if (k < N - 1) {\n                add += 2000LL * w_at(p2);\n                int bidx = k + 1;\n                if (bidx < (int)curPref.size()) add -= llabs((long long)p2 - curPref[bidx]);\n            }\n\n            long long val = base + add;\n            if (val > ndp[p2]) { ndp[p2] = val; par[k + 1][p2] = (int16_t)bestIdx[lim]; }\n        }\n        for (int p = 0; p <= W; p++) dp[p] = ndp[p];\n    }\n\n    int p = W;\n    if (dp[p] <= NINF/4) {\n        vector<int> h = need;\n        int s = accumulate(h.begin(), h.end(), 0);\n        h.back() += (W - s);\n        return h;\n    }\n\n    vector<int> h(N, 1);\n    for (int k = N - 1; k >= 0; k--) {\n        int pPrev = par[k + 1][p];\n        if (pPrev < 0) pPrev = max(0, p - need[k]);\n        h[k] = p - pPrev;\n        p = pPrev;\n    }\n    int sumH = accumulate(h.begin(), h.end(), 0);\n    h.back() += (W - sumH);\n    if (h.back() <= 0) h.back() = 1;\n    return h;\n}\n\n// Greedy adjacent swaps improving neighbor match count (keeps multiset).\nstatic void greedy_adj_swaps(vector<int>& h,\n                             const bitset<W+1>* prevIn,\n                             const bitset<W+1>* nextIn,\n                             vector<int>& pref,\n                             bitset<W+1>& in) {\n    int N = (int)h.size();\n    auto w_at = [&](int y)->int{\n        int w = 0;\n        if (prevIn && prevIn->test(y)) w++;\n        if (nextIn && nextIn->test(y)) w++;\n        return w;\n    };\n    bool improved = true;\n    while (improved) {\n        improved = false;\n        for (int i = 0; i < N - 1; i++) {\n            int oldY = pref[i+1];\n            int newY = pref[i] + h[i+1];\n            if (oldY == newY) continue;\n            if (w_at(newY) > w_at(oldY)) {\n                swap(h[i], h[i+1]);\n                pref[i+1] = newY;\n                in.reset(oldY);\n                in.set(newY);\n                improved = true;\n            }\n        }\n    }\n}\n\nstruct Cand {\n    vector<int> h;           // physical order\n    bitset<W+1> in;          // boundary set\n    long long pen;           // shortage penalty\n};\n\nstatic inline long long penalty_for_day(const vector<int>& h_phys, const vector<int>& a_sorted) {\n    vector<int> hs = h_phys;\n    sort(hs.begin(), hs.end());\n    long long pen = 0;\n    int N = (int)hs.size();\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * W * hs[k];\n        if ((long long)a_sorted[k] > area) pen += 100LL * ((long long)a_sorted[k] - area);\n    }\n    return pen;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Win, D, N;\n    cin >> Win >> D >> N;\n    (void)Win;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) for (int k = 0; k < N; k++) cin >> a[d][k];\n\n    vector<vector<int>> need(D, vector<int>(N));\n    vector<int> sumNeed(D, 0);\n    vector<char> feasibleDay(D, 0);\n    for (int d = 0; d < D; d++) {\n        int s = 0;\n        for (int k = 0; k < N; k++) {\n            need[d][k] = max(1, (a[d][k] + W - 1) / W);\n            s += need[d][k];\n        }\n        sumNeed[d] = s;\n        feasibleDay[d] = (s <= W);\n    }\n\n    // Initial heights\n    vector<vector<int>> h(D, vector<int>(N, 1));\n    for (int d = 0; d < D; d++) {\n        if (feasibleDay[d]) {\n            h[d] = need[d];\n            h[d].back() += (W - sumNeed[d]);\n        } else {\n            h[d] = multiset_infeasible_minpenalty(a[d], need[d]);\n        }\n        int s = accumulate(h[d].begin(), h[d].end(), 0);\n        h[d].back() += (W - s);\n    }\n\n    // Build boundary sets\n    vector<bitset<W+1>> in(D);\n    vector<vector<int>> pref(D);\n    for (int d = 0; d < D; d++) build_in_pref(h[d], in[d], pref[d]);\n\n    // Coordinate descent with DP (feasible) + greedy swaps\n    const int ITER = 4;\n    for (int it = 0; it < ITER; it++) {\n        for (int d = 0; d < D; d++) {\n            const bitset<W+1>* pPrev = (d > 0 ? &in[d-1] : nullptr);\n            const bitset<W+1>* pNext = (d + 1 < D ? &in[d+1] : nullptr);\n            if (feasibleDay[d]) {\n                h[d] = dp_feasible_setbased(need[d], pPrev, pNext, pref[d]);\n                int s = accumulate(h[d].begin(), h[d].end(), 0);\n                h[d].back() += (W - s);\n                build_in_pref(h[d], in[d], pref[d]);\n            }\n            greedy_adj_swaps(h[d], pPrev, pNext, pref[d], in[d]);\n        }\n    }\n\n    // Prepare sorted multiset arrays for feasible days\n    vector<array<int,55>> sortedH(D);\n    for (int d = 0; d < D; d++) if (feasibleDay[d]) {\n        vector<int> tmp = h[d];\n        sort(tmp.begin(), tmp.end());\n        for (int i = 0; i < N; i++) sortedH[d][i] = tmp[i];\n        if (!dominates_need_arr(sortedH[d].data(), need[d], N)) {\n            tmp = need[d];\n            tmp.back() += (W - sumNeed[d]);\n            sort(tmp.begin(), tmp.end());\n            for (int i = 0; i < N; i++) sortedH[d][i] = tmp[i];\n        }\n    }\n\n    // Partition cost computation\n    auto compute_part_cost = [&]() -> long long {\n        long long cost = 0;\n        for (int d = 1; d < D; d++) {\n            int inter = (int)((in[d] & in[d-1]).count());\n            cost += 2000LL * ((N - 1) - inter);\n        }\n        return cost;\n    };\n\n    auto delta_part_one_boundary = [&](int d, int oldY, int newY) -> long long {\n        long long delta = 0;\n        if (d > 0) delta += 2000LL * ((int)in[d-1].test(oldY) - (int)in[d-1].test(newY));\n        if (d + 1 < D) delta += 2000LL * ((int)in[d+1].test(oldY) - (int)in[d+1].test(newY));\n        return delta;\n    };\n\n    // SA on partition cost only; infeasible: swaps only; feasible: swap/shift/jump with dominance check\n    XorShift rng;\n    auto t_start = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - t_start).count();\n    };\n\n    long long partCost = compute_part_cost();\n    long long bestPart = partCost;\n    auto bestH = h;\n\n    const double TL = 2.75; // keep time for final DP smoothing\n    const double T0 = 6000.0, T1 = 50.0;\n\n    auto accept = [&](long long delta) -> bool {\n        if (delta <= 0) return true;\n        double t = elapsed() / TL;\n        double T = T0 * (1.0 - t) + T1 * t;\n        double prob = exp(-(double)delta / T);\n        return rng.next_double() < prob;\n    };\n\n    while (elapsed() < TL) {\n        int d = rng.next_int(D);\n        int i = rng.next_int(N - 1);\n        int b = i + 1;\n\n        int oldY = pref[d][b];\n        int P = pref[d][i];\n        int low = P + 1;\n        int high = pref[d][i + 2] - 1;\n        if (low > high) continue;\n\n        bool feas = feasibleDay[d];\n        int typ = rng.next_int(100);\n        if (!feas) typ = 0; // swaps only\n\n        if (typ < 35) {\n            // swap\n            int newY = P + h[d][i + 1];\n            if (newY == oldY) continue;\n            long long dPart = delta_part_one_boundary(d, oldY, newY);\n            if (!accept(dPart)) continue;\n\n            swap(h[d][i], h[d][i + 1]);\n            pref[d][b] = newY;\n            in[d].reset(oldY);\n            in[d].set(newY);\n            partCost += dPart;\n\n        } else if (typ < 65) {\n            // targeted shift (+1 or -1), choose better direction\n            long long bestDelta = (1LL<<60);\n            int bestDir = 0;\n            for (int dir : {+1, -1}) {\n                if (dir == +1 && h[d][i + 1] <= 1) continue;\n                if (dir == -1 && h[d][i] <= 1) continue;\n                int newY = oldY + dir;\n                if (!(low <= newY && newY <= high)) continue;\n                long long dPart = delta_part_one_boundary(d, oldY, newY);\n                if (dPart < bestDelta) { bestDelta = dPart; bestDir = dir; }\n            }\n            if (bestDir == 0) continue;\n\n            int newY = oldY + bestDir;\n            long long dPart = delta_part_one_boundary(d, oldY, newY);\n            if (!accept(dPart)) continue;\n\n            int old0 = h[d][i], old1 = h[d][i + 1];\n            int new0 = old0 + bestDir, new1 = old1 - bestDir;\n            if (new0 <= 0 || new1 <= 0) continue;\n\n            int backup[55];\n            memcpy(backup, sortedH[d].data(), sizeof(int)*N);\n            replace2_sorted(sortedH[d].data(), N, old0, old1, new0, new1);\n            if (!dominates_need_arr(sortedH[d].data(), need[d], N)) {\n                memcpy(sortedH[d].data(), backup, sizeof(int)*N);\n                continue;\n            }\n\n            h[d][i] = new0; h[d][i + 1] = new1;\n            pref[d][b] = newY;\n            in[d].reset(oldY);\n            in[d].set(newY);\n            partCost += dPart;\n\n        } else {\n            // targeted jump: choose best target boundary y among both neighbors within [low,high]\n            vector<int> candidates;\n            candidates.reserve(100);\n            if (d > 0) for (int bb = 1; bb <= N - 1; bb++) {\n                int y = pref[d-1][bb];\n                if (y != oldY && low <= y && y <= high) candidates.push_back(y);\n            }\n            if (d + 1 < D) for (int bb = 1; bb <= N - 1; bb++) {\n                int y = pref[d+1][bb];\n                if (y != oldY && low <= y && y <= high) candidates.push_back(y);\n            }\n            if (candidates.empty()) continue;\n\n            // pick best few by delta, then sample among them to keep exploration\n            struct Item { long long delta; int y; };\n            array<Item, 12> best; int bestCnt = 0;\n            for (int y : candidates) {\n                long long dPart = delta_part_one_boundary(d, oldY, y);\n                // keep top 12 smallest deltas\n                if (bestCnt < (int)best.size()) {\n                    best[bestCnt++] = {dPart, y};\n                    if (bestCnt == (int)best.size())\n                        nth_element(best.begin(), best.begin()+bestCnt/2, best.begin()+bestCnt,\n                                    [](const Item& a, const Item& b){ return a.delta < b.delta; });\n                } else {\n                    // find current worst\n                    int wi = 0;\n                    for (int t = 1; t < bestCnt; t++) if (best[t].delta > best[wi].delta) wi = t;\n                    if (dPart < best[wi].delta) best[wi] = {dPart, y};\n                }\n            }\n            int pick = rng.next_int(bestCnt);\n            int targetY = best[pick].y;\n            long long dPart = best[pick].delta;\n\n            int t = targetY - oldY;\n            int old0 = h[d][i], old1 = h[d][i + 1];\n            int new0 = old0 + t, new1 = old1 - t;\n            if (new0 <= 0 || new1 <= 0) continue;\n\n            if (!accept(dPart)) continue;\n\n            int backup[55];\n            memcpy(backup, sortedH[d].data(), sizeof(int)*N);\n            replace2_sorted(sortedH[d].data(), N, old0, old1, new0, new1);\n            if (!dominates_need_arr(sortedH[d].data(), need[d], N)) {\n                memcpy(sortedH[d].data(), backup, sizeof(int)*N);\n                continue;\n            }\n\n            h[d][i] = new0; h[d][i + 1] = new1;\n            pref[d][b] = targetY;\n            in[d].reset(oldY);\n            in[d].set(targetY);\n            partCost += dPart;\n        }\n\n        if (partCost < bestPart) {\n            bestPart = partCost;\n            bestH = h;\n        }\n    }\n\n    h.swap(bestH);\n\n    // Rebuild in/pref after SA\n    for (int d = 0; d < D; d++) build_in_pref(h[d], in[d], pref[d]);\n\n    // Final greedy snap pass (2 passes) on feasible days\n    for (int d = 0; d < D; d++) if (feasibleDay[d]) {\n        vector<int> tmp = h[d];\n        sort(tmp.begin(), tmp.end());\n        for (int i = 0; i < N; i++) sortedH[d][i] = tmp[i];\n    }\n    for (int pass = 0; pass < 2; pass++) {\n        for (int d = 0; d < D; d++) {\n            if (!feasibleDay[d]) continue;\n            for (int i = 0; i < N - 1; i++) {\n                int b = i + 1;\n                int oldY = pref[d][b];\n                int P = pref[d][i];\n                int low = P + 1, high = pref[d][i + 2] - 1;\n                if (low > high) continue;\n\n                auto tryY = [&](int y) -> long long {\n                    if (y == oldY) return 0;\n                    if (!(low <= y && y <= high)) return 0;\n                    long long dPart = delta_part_one_boundary(d, oldY, y);\n                    if (dPart >= 0) return 0;\n                    int t = y - oldY;\n                    int old0 = h[d][i], old1 = h[d][i + 1];\n                    int new0 = old0 + t, new1 = old1 - t;\n                    if (new0 <= 0 || new1 <= 0) return 0;\n                    int backup[55];\n                    memcpy(backup, sortedH[d].data(), sizeof(int)*N);\n                    replace2_sorted(sortedH[d].data(), N, old0, old1, new0, new1);\n                    bool ok = dominates_need_arr(sortedH[d].data(), need[d], N);\n                    memcpy(sortedH[d].data(), backup, sizeof(int)*N);\n                    if (!ok) return 0;\n                    return dPart;\n                };\n\n                long long bestDelta = 0;\n                int bestY = -1;\n                if (d > 0) for (int bb = 1; bb <= N - 1; bb++) {\n                    int y = pref[d-1][bb];\n                    long long dd = tryY(y);\n                    if (dd < bestDelta) { bestDelta = dd; bestY = y; }\n                }\n                if (d + 1 < D) for (int bb = 1; bb <= N - 1; bb++) {\n                    int y = pref[d+1][bb];\n                    long long dd = tryY(y);\n                    if (dd < bestDelta) { bestDelta = dd; bestY = y; }\n                }\n\n                if (bestY != -1) {\n                    int t = bestY - oldY;\n                    int old0 = h[d][i], old1 = h[d][i + 1];\n                    int new0 = old0 + t, new1 = old1 - t;\n                    replace2_sorted(sortedH[d].data(), N, old0, old1, new0, new1);\n                    h[d][i] = new0; h[d][i + 1] = new1;\n                    pref[d][b] = bestY;\n                    in[d].reset(oldY);\n                    in[d].set(bestY);\n                }\n            }\n        }\n    }\n\n    // Candidate DP smoothing over days (small candidate set) to encourage exact reuse\n    auto make_sorted_asc = [&](const vector<int>& hh){\n        vector<int> t = hh;\n        sort(t.begin(), t.end());\n        return t;\n    };\n    auto make_sorted_desc = [&](const vector<int>& hh){\n        vector<int> t = hh;\n        sort(t.begin(), t.end());\n        reverse(t.begin(), t.end());\n        return t;\n    };\n\n    vector<vector<Cand>> cands(D);\n    const int R = 3;\n    for (int d = 0; d < D; d++) {\n        vector<vector<int>> raw;\n        raw.reserve(64);\n        raw.push_back(h[d]);\n        raw.push_back(make_sorted_asc(h[d]));\n        raw.push_back(make_sorted_desc(h[d]));\n\n        // add DP variants (feasible days only)\n        if (feasibleDay[d]) {\n            const bitset<W+1>* pPrev = (d > 0 ? &in[d-1] : nullptr);\n            const bitset<W+1>* pNext = (d + 1 < D ? &in[d+1] : nullptr);\n            raw.push_back(dp_feasible_setbased(need[d], pPrev, pNext, pref[d]));\n            raw.push_back(dp_feasible_setbased(need[d], pPrev, nullptr, pref[d]));\n            raw.push_back(dp_feasible_setbased(need[d], nullptr, pNext, pref[d]));\n        }\n\n        for (int dd = max(0, d - R); dd <= min(D - 1, d + R); dd++) {\n            raw.push_back(h[dd]);\n            raw.push_back(make_sorted_asc(h[dd]));\n            raw.push_back(make_sorted_desc(h[dd]));\n        }\n\n        vector<vector<int>> uniq;\n        for (auto &v : raw) {\n            if ((int)v.size() != N) continue;\n            int s = accumulate(v.begin(), v.end(), 0);\n            if (s != W) {\n                // fix by pushing diff to last (keep positive)\n                v.back() += (W - s);\n            }\n            bool okpos = true;\n            for (int x : v) if (x <= 0) { okpos = false; break; }\n            if (!okpos) continue;\n\n            bool dup = false;\n            for (auto &u : uniq) if (u == v) { dup = true; break; }\n            if (!dup) uniq.push_back(std::move(v));\n        }\n\n        cands[d].clear();\n        cands[d].reserve(uniq.size());\n        for (auto &vecH : uniq) {\n            Cand c;\n            c.h = vecH;\n            vector<int> tmpPref;\n            build_in_pref(c.h, c.in, tmpPref);\n            c.pen = penalty_for_day(c.h, a[d]);\n            cands[d].push_back(std::move(c));\n        }\n    }\n\n    auto trans_cost = [&](const Cand& A, const Cand& B)->long long{\n        int inter = (int)((A.in & B.in).count());\n        return 2000LL * ((N - 1) - inter);\n    };\n\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> prv(D);\n    for (int d = 0; d < D; d++) {\n        int K = (int)cands[d].size();\n        dp[d].assign(K, (long long)4e18);\n        prv[d].assign(K, -1);\n    }\n\n    for (int i = 0; i < (int)cands[0].size(); i++) dp[0][i] = cands[0][i].pen; // L0=0\n\n    for (int d = 1; d < D; d++) {\n        for (int i = 0; i < (int)cands[d].size(); i++) {\n            long long pen = cands[d][i].pen;\n            for (int j = 0; j < (int)cands[d-1].size(); j++) {\n                long long v = dp[d-1][j] + trans_cost(cands[d-1][j], cands[d][i]) + pen;\n                if (v < dp[d][i]) {\n                    dp[d][i] = v;\n                    prv[d][i] = j;\n                }\n            }\n        }\n    }\n\n    int bestIdx = 0;\n    for (int i = 1; i < (int)cands[D-1].size(); i++) if (dp[D-1][i] < dp[D-1][bestIdx]) bestIdx = i;\n\n    vector<vector<int>> finalH(D);\n    int cur = bestIdx;\n    for (int d = D - 1; d >= 0; d--) {\n        finalH[d] = cands[d][cur].h;\n        cur = prv[d][cur];\n        if (d == 0) break;\n    }\n    h.swap(finalH);\n\n    // Output rectangles: physical stripes; assign reservations by sorting stripe heights ascending.\n    for (int d = 0; d < D; d++) {\n        vector<array<int,4>> stripeRect(N);\n        int y = 0;\n        for (int s = 0; s < N; s++) {\n            int y2 = y + h[d][s];\n            if (s == N - 1) y2 = W;\n            stripeRect[s] = {y, 0, y2, W};\n            y = y2;\n        }\n\n        vector<int> idx(N);\n        iota(idx.begin(), idx.end(), 0);\n        stable_sort(idx.begin(), idx.end(), [&](int i, int j){\n            return h[d][i] < h[d][j];\n        });\n\n        for (int k = 0; k < N; k++) {\n            auto r = stripeRect[idx[k]];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << \"\\n\";\n        }\n    }\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t nextU32() { return (uint32_t)nextU64(); }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstatic inline uint32_t addmod(uint32_t a, uint32_t b) {\n    uint32_t s = a + b;\n    if (s >= MOD) s -= MOD;\n    return s;\n}\nstatic inline uint32_t negmod(uint32_t a) {\n    return a ? (MOD - a) : 0u;\n}\n\nstruct Action {\n    uint8_t m, p, q;\n    uint8_t idx[9];   // affected cell indices 0..80\n    uint32_t val[9];  // added values mod MOD\n};\n\nstruct DeltaBuf {\n    array<uint32_t, 81> delta{};\n    array<int, 81> vis{};\n    int iter = 1;\n    uint8_t cells[18];\n    int cnt = 0;\n\n    inline void clear() {\n        iter++;\n        if (iter == INT_MAX) { // very unlikely, but safe\n            iter = 1;\n            vis.fill(0);\n        }\n        cnt = 0;\n    }\n    inline void addCell(uint8_t c, uint32_t dv) {\n        if (dv == 0) return;\n        if (vis[c] != iter) {\n            vis[c] = iter;\n            delta[c] = dv;\n            cells[cnt++] = c;\n        } else {\n            delta[c] = addmod(delta[c], dv);\n        }\n    }\n};\n\nstatic inline int64_t add_gain_only(const Action &a, const array<uint32_t,81> &res) {\n    int64_t d = 0;\n    for (int k = 0; k < 9; k++) {\n        uint8_t c = a.idx[k];\n        uint32_t r = res[c];\n        uint32_t nr = r + a.val[k];\n        if (nr >= MOD) nr -= MOD;\n        d += (int64_t)nr - (int64_t)r;\n    }\n    return d;\n}\n\nstatic inline int64_t compute_change(int oldId, int newId,\n                                    const vector<Action> &actions,\n                                    const array<uint32_t,81> &res,\n                                    DeltaBuf &buf) {\n    buf.clear();\n    if (oldId != -1) {\n        const auto &a = actions[oldId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], negmod(a.val[k]));\n    }\n    if (newId != -1) {\n        const auto &a = actions[newId];\n        for (int k = 0; k < 9; k++) buf.addCell(a.idx[k], a.val[k]);\n    }\n    int64_t dscore = 0;\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        dscore += (int64_t)nr - (int64_t)r;\n    }\n    return dscore;\n}\n\nstatic inline void apply_change(const DeltaBuf &buf, array<uint32_t,81> &res) {\n    for (int i = 0; i < buf.cnt; i++) {\n        uint8_t c = buf.cells[i];\n        uint32_t r = res[c];\n        uint32_t dv = buf.delta[c];\n        uint32_t nr = r + dv;\n        if (nr >= MOD) nr -= MOD;\n        res[c] = nr;\n    }\n}\n\nstatic inline int64_t score_of(const array<uint32_t,81> &res) {\n    int64_t s = 0;\n    for (uint32_t v : res) s += v;\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K; // N=9,M=20,K=81\n\n    array<uint32_t,81> a0{};\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        uint64_t x; cin >> x;\n        a0[i*N + j] = (uint32_t)(x % MOD);\n    }\n\n    vector<array<uint32_t,9>> stamps(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n            uint64_t x; cin >> x;\n            stamps[m][i*3 + j] = (uint32_t)(x % MOD);\n        }\n    }\n\n    // Precompute actions\n    vector<Action> actions;\n    actions.reserve(M * (N-2) * (N-2));\n    // mapping: stamp m, pos (p*7+q) -> action id\n    array<array<int, 49>, 20> idOf{};\n    for (int m = 0; m < M; m++) for (int pos = 0; pos < 49; pos++) idOf[m][pos] = -1;\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action act;\n                act.m = (uint8_t)m;\n                act.p = (uint8_t)p;\n                act.q = (uint8_t)q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) {\n                    int bi = p + i, bj = q + j;\n                    act.idx[t] = (uint8_t)(bi * N + bj);\n                    act.val[t] = stamps[m][i*3 + j];\n                    t++;\n                }\n                int id = (int)actions.size();\n                actions.push_back(act);\n                int pos = p * 7 + q;\n                idOf[m][pos] = id;\n            }\n        }\n    }\n    const int A = (int)actions.size(); // 980\n\n    // Seed RNG input-dependent\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 81; i++) seed = seed * 1000003ULL + a0[i];\n    XorShift64 rng(seed);\n\n    // exp lookup for x in [-20,0]\n    static vector<double> expTab;\n    if (expTab.empty()) {\n        const int STEPS = 8192;\n        expTab.resize(STEPS + 1);\n        for (int i = 0; i <= STEPS; i++) {\n            double x = -20.0 * (double)i / (double)STEPS;\n            expTab[i] = exp(x);\n        }\n    }\n    auto exp_lookup = [&](double x)->double { // x in [-20,0]\n        if (x <= -20.0) return 0.0;\n        if (x >= 0.0) return 1.0;\n        const int STEPS = (int)expTab.size() - 1;\n        int idx = (int)llround((-x) * (double)STEPS / 20.0);\n        if (idx < 0) idx = 0;\n        if (idx > STEPS) idx = STEPS;\n        return expTab[idx];\n    };\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n\n    auto elapsedSec = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    auto best_stamp_for_pos = [&](int pos, const array<uint32_t,81> &res)->int {\n        int bestId = -1;\n        int64_t bestGain = LLONG_MIN;\n        for (int m = 0; m < M; m++) {\n            int id = idOf[m][pos];\n            int64_t g = add_gain_only(actions[id], res);\n            if (g > bestGain) {\n                bestGain = g;\n                bestId = id;\n            }\n        }\n        return bestId;\n    };\n\n    // Build solution from ops\n    auto rebuild = [&](const vector<int> &ops, array<uint32_t,81> &res)->int64_t {\n        res = a0;\n        for (int id : ops) {\n            if (id == -1) continue;\n            const auto &a = actions[id];\n            for (int k = 0; k < 9; k++) {\n                uint8_t c = a.idx[k];\n                uint32_t nr = res[c] + a.val[k];\n                if (nr >= MOD) nr -= MOD;\n                res[c] = nr;\n            }\n        }\n        return score_of(res);\n    };\n\n    // One run: init then SA+LNS, return best\n    vector<int> globalBestOps(K, -1);\n    int64_t globalBestScore = score_of(a0);\n\n    DeltaBuf buf;\n\n    auto do_run = [&](int mode, double endTimeSec) {\n        // mode 0: greedy with small randomness\n        // mode 1: randomized by position (choose pos random, best stamp for that pos wrt current)\n        vector<int> ops(K, -1);\n        array<uint32_t,81> res = a0;\n        int64_t score = score_of(res);\n\n        if (mode == 0) {\n            // Greedy fill, but sometimes pick among top few to diversify\n            for (int slot = 0; slot < K; slot++) {\n                int best1 = -1, best2 = -1, best3 = -1;\n                int64_t g1 = 0, g2 = 0, g3 = 0;\n                for (int id = 0; id < A; id++) {\n                    int64_t g = add_gain_only(actions[id], res);\n                    if (g > g1) {\n                        best3 = best2; g3 = g2;\n                        best2 = best1; g2 = g1;\n                        best1 = id;    g1 = g;\n                    } else if (g > g2) {\n                        best3 = best2; g3 = g2;\n                        best2 = id;    g2 = g;\n                    } else if (g > g3) {\n                        best3 = id;    g3 = g;\n                    }\n                }\n                if (best1 == -1 || g1 <= 0) break;\n                int pick = best1;\n                // 15%: pick best2/3 if close\n                if (rng.nextInt(100) < 15) {\n                    int r = rng.nextInt(3);\n                    if (r == 1 && best2 != -1) pick = best2;\n                    if (r == 2 && best3 != -1) pick = best3;\n                }\n                ops[slot] = pick;\n                const auto &a = actions[pick];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n                score += add_gain_only(a, res); // WRONG if used after applying; avoid; keep score by recomputing delta before apply\n                // Fix: we won't use this broken score update; recompute after greedy loop.\n                // (We keep this line harmless by overwriting score below.)\n            }\n            score = score_of(res);\n        } else {\n            // Randomized position-based construction\n            for (int slot = 0; slot < K; slot++) {\n                int pos = rng.nextInt(49);\n                int id = best_stamp_for_pos(pos, res);\n                // small chance to take random stamp instead\n                if (rng.nextInt(100) < 10) {\n                    int m = rng.nextInt(M);\n                    id = idOf[m][pos];\n                }\n                ops[slot] = id;\n                const auto &a = actions[id];\n                for (int k = 0; k < 9; k++) {\n                    uint8_t c = a.idx[k];\n                    uint32_t nr = res[c] + a.val[k];\n                    if (nr >= MOD) nr -= MOD;\n                    res[c] = nr;\n                }\n            }\n            score = score_of(res);\n        }\n\n        // track local best\n        vector<int> bestOps = ops;\n        int64_t bestScore = score;\n        array<uint32_t,81> bestRes = res;\n\n        // SA parameters\n        const double T0 = 2.0e9;\n        const double T1 = 2.0e6;\n        const double logRatio = log(T1 / T0);\n\n        double lastCheck = elapsedSec();\n        double T = T0;\n        uint64_t iters = 0;\n\n        auto accept_move = [&](int64_t d)->bool {\n            if (d >= 0) return true;\n            double x = (double)d / T; // negative\n            double prob = exp_lookup(x);\n            return rng.nextDouble() < prob;\n        };\n\n        // SA loop\n        while (true) {\n            iters++;\n\n            if ((iters & 2047ull) == 0) {\n                double e = elapsedSec();\n                if (e >= endTimeSec) break;\n                double prog = (e - lastCheck) / max(1e-9, (endTimeSec - lastCheck)); // not great; use global progress instead\n                (void)prog;\n                double globalProg = min(1.0, e / endTimeSec);\n                T = T0 * exp(logRatio * globalProg);\n            }\n\n            int moveType = rng.nextInt(100);\n            if (moveType < 70) {\n                // 1-slot replace\n                int slot = rng.nextInt(K);\n                int oldId = ops[slot];\n\n                int newId = -1;\n                int r = rng.nextInt(100);\n\n                if (r < 10) {\n                    newId = -1;\n                } else if (r < 40) {\n                    // random action\n                    newId = rng.nextInt(A);\n                } else if (r < 65) {\n                    // best stamp for random pos\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1 && r < 85) {\n                    // same position, best stamp\n                    int pos = actions[oldId].p * 7 + actions[oldId].q;\n                    newId = best_stamp_for_pos(pos, res);\n                } else if (oldId != -1) {\n                    // same stamp, random position\n                    int m = actions[oldId].m;\n                    int pos = rng.nextInt(49);\n                    newId = idOf[m][pos];\n                } else {\n                    int pos = rng.nextInt(49);\n                    newId = best_stamp_for_pos(pos, res);\n                }\n\n                if (newId == oldId) continue;\n\n                int64_t d = compute_change(oldId, newId, actions, res, buf);\n                if (accept_move(d)) {\n                    apply_change(buf, res);\n                    score += d;\n                    ops[slot] = newId;\n\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else if (moveType < 90) {\n                // 2-slot replace\n                int s1 = rng.nextInt(K);\n                int s2 = rng.nextInt(K);\n                if (s1 == s2) continue;\n                int old1 = ops[s1], old2 = ops[s2];\n\n                int new1, new2;\n                // propose using strong candidates sometimes\n                auto propose = [&](int oldId)->int {\n                    int rr = rng.nextInt(100);\n                    if (rr < 10) return -1;\n                    if (rr < 35) return rng.nextInt(A);\n                    if (rr < 70) {\n                        int pos = rng.nextInt(49);\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    if (oldId != -1) {\n                        int pos = actions[oldId].p * 7 + actions[oldId].q;\n                        return best_stamp_for_pos(pos, res);\n                    }\n                    int pos = rng.nextInt(49);\n                    return best_stamp_for_pos(pos, res);\n                };\n                new1 = propose(old1);\n                new2 = propose(old2);\n                if (new1 == old1 && new2 == old2) continue;\n\n                // apply combined by sequential compute in a temp copy (cheap, 81 cells)\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // change slot1\n                int64_t d1 = compute_change(old1, new1, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d1;\n                // change slot2 (note: use updated tmpRes)\n                int64_t d2 = compute_change(old2, new2, actions, tmpRes, buf);\n                apply_change(buf, tmpRes);\n                tmpScore += d2;\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    res = tmpRes;\n                    score = tmpScore;\n                    ops[s1] = new1;\n                    ops[s2] = new2;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            } else {\n                // LNS: remove t random slots, then greedily refill\n                int t = 6 + rng.nextInt(7); // 6..12\n                vector<int> idx(K);\n                iota(idx.begin(), idx.end(), 0);\n                for (int i = 0; i < t; i++) {\n                    int j = i + rng.nextInt(K - i);\n                    swap(idx[i], idx[j]);\n                }\n                idx.resize(t);\n\n                vector<int> tmpOps = ops;\n                array<uint32_t,81> tmpRes = res;\n                int64_t tmpScore = score;\n\n                // remove chosen slots\n                for (int slot : idx) {\n                    int oldId = tmpOps[slot];\n                    if (oldId == -1) continue;\n                    int64_t d = compute_change(oldId, -1, actions, tmpRes, buf);\n                    apply_change(buf, tmpRes);\n                    tmpScore += d;\n                    tmpOps[slot] = -1;\n                }\n\n                // greedy refill chosen slots (leave empty if bestGain <= 0 most of the time)\n                for (int slot : idx) {\n                    int bestId = -1;\n                    int64_t bestG = LLONG_MIN;\n\n                    // Use a mix: try best over all actions, but we can speed by also trying best-per-pos sometimes.\n                    // Since A=980 small, full scan is fine here.\n                    for (int id = 0; id < A; id++) {\n                        int64_t g = add_gain_only(actions[id], tmpRes);\n                        if (g > bestG) { bestG = g; bestId = id; }\n                    }\n\n                    if (bestId != -1) {\n                        bool take = (bestG > 0) || (rng.nextInt(100) < 10); // 10% take even if <=0\n                        if (take) {\n                            const auto &a = actions[bestId];\n                            for (int k = 0; k < 9; k++) {\n                                uint8_t c = a.idx[k];\n                                uint32_t nr = tmpRes[c] + a.val[k];\n                                if (nr >= MOD) nr -= MOD;\n                                tmpRes[c] = nr;\n                            }\n                            tmpOps[slot] = bestId;\n                            // update tmpScore by exact delta\n                            // (use add_gain_only on original res would be wrong; recompute via direct diff)\n                            // easiest: recompute score delta for 9 cells:\n                            // but we already updated tmpRes; so compute delta by subtracting old via storing old values:\n                            // keep it simple: compute after all refills (81 cells only).\n                        }\n                    }\n                }\n                tmpScore = score_of(tmpRes);\n\n                int64_t d = tmpScore - score;\n                if (accept_move(d)) {\n                    ops.swap(tmpOps);\n                    res = tmpRes;\n                    score = tmpScore;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                        bestRes = res;\n                    }\n                }\n            }\n        }\n\n        // Final local refinement: repeat 1-opt until no improvement or time\n        ops = bestOps;\n        score = rebuild(ops, res);\n        bool any = true;\n        while (any && elapsedSec() < endTimeSec) {\n            any = false;\n            vector<int> order(K);\n            iota(order.begin(), order.end(), 0);\n            // lightweight shuffle\n            for (int i = 0; i < K; i++) swap(order[i], order[rng.nextInt(K)]);\n\n            for (int t = 0; t < K; t++) {\n                if (elapsedSec() >= endTimeSec) break;\n                int slot = order[t];\n                int oldId = ops[slot];\n\n                int bestNew = oldId;\n                int64_t bestD = 0;\n                DeltaBuf bestBufLocal;\n\n                // try empty\n                {\n                    int64_t d = compute_change(oldId, -1, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = -1;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                // try all actions\n                for (int id = 0; id < A; id++) {\n                    if (id == oldId) continue;\n                    int64_t d = compute_change(oldId, id, actions, res, buf);\n                    if (d > bestD) {\n                        bestD = d;\n                        bestNew = id;\n                        bestBufLocal = buf;\n                    }\n                }\n\n                if (bestNew != oldId) {\n                    apply_change(bestBufLocal, res);\n                    score += bestD;\n                    ops[slot] = bestNew;\n                    any = true;\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestOps = ops;\n                    }\n                }\n            }\n        }\n\n        if (bestScore > globalBestScore) {\n            globalBestScore = bestScore;\n            globalBestOps = bestOps;\n        }\n    };\n\n    // Time budgeting: 2 runs + final polishing built-in each run\n    // Run 1: greedy-ish init\n    do_run(0, min(TL, 1.30));\n    // Run 2: randomized init, use remaining time\n    do_run(1, TL);\n\n    // Output\n    vector<tuple<int,int,int>> out;\n    out.reserve(K);\n    for (int id : globalBestOps) {\n        if (id == -1) continue;\n        const auto &a = actions[id];\n        out.emplace_back((int)a.m, (int)a.p, (int)a.q);\n    }\n    cout << out.size() << \"\\n\";\n    for (auto &[m,p,q] : out) {\n        cout << m << \" \" << p << \" \" << q << \"\\n\";\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 5;\nstatic const int MAX_TURNS = 10000;\n\nstruct Solver {\n    int A[N][N];\n    int origRow[N*N], origIdx[N*N];\n\n    int grid[N][N];              // container id or -1\n    int posR[N*N], posC[N*N];    // on grid, else (-1,-1)\n\n    int spawned[N];              // # spawned per receiving row\n    int dispMask[N];             // dispatched bitmask per dispatch-group row\n    int dispatchedCount = 0;\n\n    struct Crane {\n        int r=0,c=0;\n        bool alive=true;\n        bool holding=false;\n        int held=-1;\n        bool large=false;\n    };\n    Crane cranes[N]; // 0 large, 1..4 small\n\n    vector<string> out;\n    deque<char> plan0;\n    int turn=0;\n\n    int noDispatchTurns=0;\n\n    // mode: 0=parallel, 1=bombing, 2=solo\n    int mode=0;\n\n    static constexpr int STUCK_LIMIT = 220;\n    static constexpr int LATE_LIMIT  = 8500;\n\n    Solver(const vector<vector<int>>& Ain) : out(N, \"\") {\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            A[i][j]=Ain[i][j];\n            origRow[A[i][j]]=i;\n            origIdx[A[i][j]]=j;\n        }\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) grid[i][j]=-1;\n        for(int id=0;id<N*N;id++) posR[id]=posC[id]=-1;\n        for(int i=0;i<N;i++){ spawned[i]=0; dispMask[i]=0; }\n\n        for(int i=0;i<N;i++){\n            cranes[i].r=i; cranes[i].c=0;\n            cranes[i].alive=true;\n            cranes[i].holding=false;\n            cranes[i].held=-1;\n            cranes[i].large = (i==0);\n        }\n    }\n\n    // ===== order helpers =====\n    int expectedIndex(int t) const {\n        for(int k=0;k<N;k++) if(((dispMask[t]>>k)&1)==0) return k;\n        return N;\n    }\n    int expectedId(int t) const {\n        int k=expectedIndex(t);\n        if(k>=N) return -1;\n        return N*t + k;\n    }\n    int invCostIfDispatch(int id) const {\n        int t=id/N, idx=id%N;\n        int cost=0;\n        for(int k=0;k<idx;k++) if(((dispMask[t]>>k)&1)==0) cost++;\n        return cost;\n    }\n\n    // ===== crane helpers =====\n    bool otherCraneAt(int r,int c,int ignoreIdx) const {\n        for(int k=0;k<N;k++){\n            if(k==ignoreIdx) continue;\n            if(!cranes[k].alive) continue;\n            if(cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n    bool holdingCraneAt(int r,int c) const {\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(cranes[k].holding && cranes[k].r==r && cranes[k].c==c) return true;\n        }\n        return false;\n    }\n\n    // ===== spawn =====\n    void spawnPhase(){\n        for(int r=0;r<N;r++){\n            if(spawned[r]>=N) continue;\n            if(grid[r][0]!=-1) continue;\n            if(holdingCraneAt(r,0)) continue;\n            int id = A[r][spawned[r]++];\n            grid[r][0]=id;\n            posR[id]=r; posC[id]=0;\n        }\n    }\n\n    // ===== storage counting/selection =====\n    int countEmptyStrictStorageParallel() const {\n        int cnt=0;\n        for(int r=0;r<N;r++){\n            for(int c=0;c<N;c++){\n                if(c==4) continue;\n                if(grid[r][c]!=-1) continue;\n                if(r>0 && c==1) continue;          // keep buffers\n                if(c==0 && spawned[r]<N) continue; // active gate\n                if(otherCraneAt(r,c,0)) continue;  // large itself ok\n                cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int countEmptySoloStorage(bool allowActiveGates) const {\n        int cnt=0;\n        for(int r=0;r<N;r++){\n            for(int c=0;c<N;c++){\n                if(c==4) continue;\n                if(grid[r][c]!=-1) continue;\n                if(!allowActiveGates && c==0 && spawned[r]<N) continue;\n                if(otherCraneAt(r,c,0)) continue;\n                cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    pair<int,int> chooseParallelStorageCell(int id, int fromR, int fromC) const {\n        int t=id/N;\n        auto ok = [&](int r,int c)->bool{\n            if(c==4) return false;\n            if(grid[r][c]!=-1) return false;\n            if(r>0 && c==1) return false;\n            if(c==0 && spawned[r]<N) return false;\n            if(otherCraneAt(r,c,0)) return false;\n            return true;\n        };\n        vector<pair<int,int>> pref = {\n            {t,3},{t,2},{0,3},{0,2},{t,1},{0,1},\n            {1,3},{2,3},{3,3},{4,3},{0,0}\n        };\n        for(auto [r,c]: pref) if(ok(r,c)) return {r,c};\n\n        int bestD=INT_MAX;\n        pair<int,int> best={-1,-1};\n        for(int r=0;r<N;r++) for(int c=0;c<N;c++){\n            if(!ok(r,c)) continue;\n            int d=abs(fromR-r)+abs(fromC-c);\n            if(r==t) d-=1;\n            if(d<bestD){ bestD=d; best={r,c}; }\n        }\n        return best;\n    }\n\n    pair<int,int> chooseSoloStorageCell(int id, int fromR, int fromC) const {\n        int t=id/N;\n        for(int phase=0; phase<2; phase++){\n            bool allowActiveGates = (phase==1);\n            auto ok = [&](int r,int c)->bool{\n                if(c==4) return false;\n                if(grid[r][c]!=-1) return false;\n                if(!allowActiveGates && c==0 && spawned[r]<N) return false;\n                if(otherCraneAt(r,c,0)) return false;\n                return true;\n            };\n            vector<pair<int,int>> pref = {{t,3},{t,2},{t,1},{0,3},{0,2},{0,1},{t,0},{0,0}};\n            for(auto [r,c]: pref) if(ok(r,c)) return {r,c};\n\n            int bestD=INT_MAX;\n            pair<int,int> best={-1,-1};\n            for(int r=0;r<N;r++) for(int c=0;c<N;c++){\n                if(!ok(r,c)) continue;\n                int d=abs(fromR-r)+abs(fromC-c);\n                if(r==t) d-=1;\n                if(d<bestD){ bestD=d; best={r,c}; }\n            }\n            if(best.first!=-1) return best;\n        }\n        return {-1,-1};\n    }\n\n    // ===== BFS for large =====\n    // parallel restriction: forbid only (r>0,c==0)\n    bool forbiddenForLargeParallel(int r,int c) const { return (r>0 && c==0); }\n\n    // In parallel mode, a buffer cell (i,1) occupied by small crane i is \"vacatable\" if the small is not holding.\n    bool vacatableBufferCell(int r,int c) const {\n        if(!(r>0 && c==1)) return false;\n        const Crane &s = cranes[r];\n        if(!s.alive) return false;\n        if(s.r!=r || s.c!=1) return false;\n        if(s.holding) return false;\n        return true;\n    }\n\n    vector<char> bfsLarge(int sr,int sc,int tr,int tc,bool restrictParallel) const {\n        if(sr==tr && sc==tc) return {};\n\n        array<array<int,N>,N> dist;\n        array<array<pair<int,int>,N>,N> prev;\n        array<array<char,N>,N> pm;\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++){\n            dist[i][j]=-1; prev[i][j]={-1,-1}; pm[i][j]='?';\n        }\n\n        auto blocked = [&](int r,int c)->bool{\n            if(r<0||r>=N||c<0||c>=N) return true;\n            if(restrictParallel && forbiddenForLargeParallel(r,c)) return true;\n\n            // other cranes are obstacles, except vacatable buffer cells in parallel mode\n            for(int k=1;k<N;k++){\n                if(!cranes[k].alive) continue;\n                if(cranes[k].r==r && cranes[k].c==c){\n                    if(restrictParallel && vacatableBufferCell(r,c)) return false;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        queue<pair<int,int>> q;\n        dist[sr][sc]=0;\n        q.push({sr,sc});\n        const int dr[4]={-1,1,0,0};\n        const int dc[4]={0,0,-1,1};\n        const char mv[4]={'U','D','L','R'};\n        while(!q.empty()){\n            auto [r,c]=q.front(); q.pop();\n            for(int k=0;k<4;k++){\n                int nr=r+dr[k], nc=c+dc[k];\n                if(blocked(nr,nc)) continue;\n                if(dist[nr][nc]!=-1) continue;\n                dist[nr][nc]=dist[r][c]+1;\n                prev[nr][nc]={r,c};\n                pm[nr][nc]=mv[k];\n                q.push({nr,nc});\n            }\n        }\n        if(dist[tr][tc]==-1) return {};\n        vector<char> path;\n        int r=tr,c=tc;\n        while(!(r==sr && c==sc)){\n            path.push_back(pm[r][c]);\n            auto p=prev[r][c];\n            r=p.first; c=p.second;\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    int distLarge(int sr,int sc,int tr,int tc,bool restrictParallel) const {\n        if(sr==tr && sc==tc) return 0;\n        auto p=bfsLarge(sr,sc,tr,tc,restrictParallel);\n        if(p.empty()) return 1e9;\n        return (int)p.size();\n    }\n\n    // ===== small cranes =====\n    char decideSmallParallel(int i, int lockRow) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n\n        int c=cr.c;\n        if(lockRow==i){\n            // evacuate buffer so large can pass/enter\n            if(c==1){\n                if(cr.holding){\n                    if(grid[i][1]==-1) return 'Q';\n                    return '.';\n                } else {\n                    return 'L';\n                }\n            }\n            // if holding at gate, prevent moving into buffer\n            return '.';\n        }\n\n        if(cr.holding){\n            if(c==0){\n                if(grid[i][1]==-1) return 'R';\n                return '.';\n            }else{\n                if(grid[i][1]==-1) return 'Q';\n                return '.';\n            }\n        }else{\n            if(c==1) return 'L';\n            if(grid[i][0]!=-1 && grid[i][1]==-1) return 'P';\n            return '.';\n        }\n    }\n\n    char decideSmallBomb(int i) const {\n        const Crane &cr = cranes[i];\n        if(!cr.alive) return '.';\n        if(cr.holding){\n            if(grid[cr.r][cr.c]==-1) return 'Q';\n            return '.';\n        }\n        return 'B';\n    }\n\n    // ===== planning helpers =====\n    bool buildDispatchPlan(int pr,int pc,int id,bool restrictParallel){\n        plan0.clear();\n        Crane &L = cranes[0];\n        int t=id/N;\n\n        auto p1=bfsLarge(L.r,L.c,pr,pc,restrictParallel);\n        if(!(L.r==pr && L.c==pc) && p1.empty()) return false;\n        auto p2=bfsLarge(pr,pc,t,4,restrictParallel);\n        if(!(pr==t && pc==4) && p2.empty()) return false;\n\n        for(char m: p1) plan0.push_back(m);\n        plan0.push_back('P');\n        for(char m: p2) plan0.push_back(m);\n        plan0.push_back('Q');\n        return true;\n    }\n\n    bool buildPickStorePlan(int pr,int pc,int id,bool restrictParallel){\n        plan0.clear();\n        Crane &L = cranes[0];\n\n        if(restrictParallel && pr>0 && pc==0) return false; // never enter small gate cells\n\n        pair<int,int> st = restrictParallel ? chooseParallelStorageCell(id, pr, pc)\n                                            : chooseSoloStorageCell(id, pr, pc);\n        if(st.first==-1) return false;\n\n        auto p1=bfsLarge(L.r,L.c,pr,pc,restrictParallel);\n        if(!(L.r==pr && L.c==pc) && p1.empty()) return false;\n        auto p2=bfsLarge(pr,pc,st.first,st.second,restrictParallel);\n        if(!(pr==st.first && pc==st.second) && p2.empty()) return false;\n\n        for(char m: p1) plan0.push_back(m);\n        plan0.push_back('P');\n        for(char m: p2) plan0.push_back(m);\n        plan0.push_back('Q');\n        return true;\n    }\n\n    int chooseBestExpectedOnGrid(bool restrictParallel) const {\n        const Crane &L=cranes[0];\n        int lr=L.r, lc=L.c;\n        int bestId=-1, bestCost=1e9;\n\n        for(int r=0;r<N;r++) for(int c=0;c<4;c++){\n            int id=grid[r][c];\n            if(id==-1) continue;\n\n            if(restrictParallel && r>0 && c==0) continue;\n\n            // if cell occupied by another crane:\n            // allow (r>0,c==1) if it's vacatable (small not holding); otherwise skip.\n            if(otherCraneAt(r,c,0)){\n                if(!(restrictParallel && vacatableBufferCell(r,c))) continue;\n            }\n\n            int t=id/N;\n            if(expectedId(t)!=id) continue;\n\n            int d1=distLarge(lr,lc,r,c,restrictParallel);\n            int d2=distLarge(r,c,t,4,restrictParallel);\n            if(d1>=1e9 || d2>=1e9) continue;\n            int cost=d1+d2;\n            if(cost<bestCost){ bestCost=cost; bestId=id; }\n        }\n        return bestId;\n    }\n\n    // Prefetch if expected is in buffer but small is holding there (rare) or other issues\n    int choosePrefetchExpectedBufferRow() const {\n        const Crane &L = cranes[0];\n        int lr=L.r, lc=L.c;\n        int bestRow=-1, bestCost=1e9;\n\n        for(int r=1;r<N;r++){\n            int id = grid[r][1];\n            if(id==-1) continue;\n            int t=id/N;\n            if(expectedId(t)!=id) continue;\n\n            // if buffer cell is \"vacatable\", expected selection will handle; prefetch not needed\n            if(vacatableBufferCell(r,1)) continue;\n\n            int tr=r, tc=2;\n            int d = distLarge(lr,lc,tr,tc,true);\n            if(d>=1e9) continue;\n            if(d < bestCost){\n                bestCost=d;\n                bestRow=r;\n            }\n        }\n        return bestRow;\n    }\n\n    int chooseExpectedToUncoverSolo() const {\n        pair<pair<int,int>,int> best={{INT_MAX,INT_MAX},-1};\n        int lr=cranes[0].r, lc=cranes[0].c;\n        for(int t=0;t<N;t++){\n            int id=expectedId(t);\n            if(id==-1) continue;\n            if(posR[id]!=-1) continue;\n            int r=origRow[id];\n            int oi=origIdx[id];\n            int need=max(0,(oi+1)-spawned[r]);\n            int dist=abs(lr-r)+abs(lc-0);\n            pair<int,int> key={need,dist};\n            if(key<best.first){ best.first=key; best.second=id; }\n        }\n        return best.second;\n    }\n\n    int chooseMinInvDispatchCandidateSolo(int maxInvAllowed) const {\n        const Crane &L=cranes[0];\n        int lr=L.r, lc=L.c;\n        long long bestScore=(1LL<<60);\n        int bestId=-1;\n\n        for(int r=0;r<N;r++) for(int c=0;c<4;c++){\n            int id=grid[r][c];\n            if(id==-1) continue;\n            if(otherCraneAt(r,c,0)) continue;\n\n            int inv=invCostIfDispatch(id);\n            if(inv>maxInvAllowed) continue;\n\n            int t=id/N;\n            int d1=distLarge(lr,lc,r,c,false);\n            int d2=distLarge(r,c,t,4,false);\n            if(d1>=1e9 || d2>=1e9) continue;\n            long long score = 100000LL*inv + 10LL*(d1+d2);\n            if(score<bestScore){ bestScore=score; bestId=id; }\n        }\n        return bestId;\n    }\n\n    // ===== large planning =====\n    void buildLargePlanParallel(){\n        plan0.clear();\n        Crane &L=cranes[0];\n\n        if(L.holding){\n            int id=L.held;\n            int t=id/N;\n            if(expectedId(t)==id){\n                auto p=bfsLarge(L.r,L.c,t,4,true);\n                for(char m:p) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            auto st=chooseParallelStorageCell(id,L.r,L.c);\n            if(st.first!=-1){\n                auto p=bfsLarge(L.r,L.c,st.first,st.second,true);\n                for(char m:p) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            mode=1; plan0.clear();\n            return;\n        }\n\n        int exp=chooseBestExpectedOnGrid(true);\n        if(exp!=-1){\n            int pr=posR[exp], pc=posC[exp];\n            if(pr!=-1 && buildDispatchPlan(pr,pc,exp,true)) return;\n        }\n\n        int pre = choosePrefetchExpectedBufferRow();\n        if(pre!=-1){\n            int tr=pre, tc=2;\n            auto p=bfsLarge(L.r,L.c,tr,tc,true);\n            if(!p.empty()){\n                for(char m: p) plan0.push_back(m);\n                return;\n            }\n            plan0.push_back('.');\n            return;\n        }\n\n        // clear nearest buffer (avoid only if small is holding ON the buffer cell, because then it cannot vacate)\n        int lr=L.r, lc=L.c;\n        int bestRow=-1, bestD=1e9;\n        for(int i=1;i<N;i++){\n            if(grid[i][1]==-1) continue;\n            const Crane &s = cranes[i];\n            if(s.alive && s.r==i && s.c==1 && s.holding) continue; // cannot vacate\n            int d=distLarge(lr,lc,i,1,true);\n            if(d<bestD){ bestD=d; bestRow=i; }\n        }\n        if(bestRow!=-1){\n            int id=grid[bestRow][1];\n            if(id!=-1 && buildPickStorePlan(bestRow,1,id,true)) return;\n        }\n\n        // clear row0 gate\n        if(grid[0][0]!=-1){\n            int id=grid[0][0];\n            if(buildPickStorePlan(0,0,id,true)) return;\n        }\n\n        if(countEmptyStrictStorageParallel() <= 0 && chooseBestExpectedOnGrid(true)==-1){\n            mode=1;\n            plan0.clear();\n            return;\n        }\n\n        plan0.push_back('.');\n    }\n\n    void buildLargePlanSolo(){\n        plan0.clear();\n        Crane &L=cranes[0];\n\n        if(L.holding){\n            int id=L.held;\n            int t=id/N;\n            if(expectedId(t)==id){\n                auto p=bfsLarge(L.r,L.c,t,4,false);\n                for(char m:p) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            auto st=chooseSoloStorageCell(id,L.r,L.c);\n            if(st.first!=-1){\n                auto p=bfsLarge(L.r,L.c,st.first,st.second,false);\n                for(char m:p) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            }\n            auto p=bfsLarge(L.r,L.c,t,4,false);\n            for(char m:p) plan0.push_back(m);\n            plan0.push_back('Q');\n            return;\n        }\n\n        int exp=chooseBestExpectedOnGrid(false);\n        if(exp!=-1){\n            int pr=posR[exp], pc=posC[exp];\n            if(pr!=-1 && buildDispatchPlan(pr,pc,exp,false)) return;\n        }\n\n        if(countEmptySoloStorage(false) == 0){\n            int cand = chooseMinInvDispatchCandidateSolo(1);\n            if(cand==-1) cand = chooseMinInvDispatchCandidateSolo(4);\n            if(cand!=-1){\n                int pr=posR[cand], pc=posC[cand];\n                if(pr!=-1 && buildDispatchPlan(pr,pc,cand,false)) return;\n            }\n            plan0.push_back('.');\n            return;\n        }\n\n        int target = chooseExpectedToUncoverSolo();\n        if(target!=-1){\n            int r = origRow[target];\n            if(grid[r][0]==-1){\n                plan0.push_back('.');\n                return;\n            }\n            int id = grid[r][0];\n\n            auto p1=bfsLarge(L.r,L.c,r,0,false);\n            for(char m:p1) plan0.push_back(m);\n            plan0.push_back('P');\n\n            int t=id/N;\n            if(expectedId(t)==id){\n                auto p2=bfsLarge(r,0,t,4,false);\n                for(char m:p2) plan0.push_back(m);\n                plan0.push_back('Q');\n                return;\n            } else {\n                auto st=chooseSoloStorageCell(id,r,0);\n                if(st.first!=-1){\n                    auto p2=bfsLarge(r,0,st.first,st.second,false);\n                    for(char m:p2) plan0.push_back(m);\n                    plan0.push_back('Q');\n                    return;\n                } else {\n                    auto p2=bfsLarge(r,0,t,4,false);\n                    for(char m:p2) plan0.push_back(m);\n                    plan0.push_back('Q');\n                    return;\n                }\n            }\n        }\n\n        plan0.push_back('.');\n    }\n\n    // ===== validation & apply =====\n    struct MoveInfo { int sr,sc, dr,dc; };\n\n    bool validateActions(const array<char,N>& act) const {\n        array<MoveInfo,N> mv;\n        array<bool,N> willBomb{};\n        for(int k=0;k<N;k++){\n            const Crane &cr=cranes[k];\n            willBomb[k]=false;\n\n            if(!cr.alive){\n                if(act[k] != '.') return false;\n                mv[k]={cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n            char a=act[k];\n            if(a=='B'){\n                if(cr.holding) return false;\n                willBomb[k]=true;\n                mv[k]={cr.r,cr.c,cr.r,cr.c};\n                continue;\n            }\n\n            int r=cr.r,c=cr.c,nr=r,nc=c;\n            if(a=='U') nr--;\n            else if(a=='D') nr++;\n            else if(a=='L') nc--;\n            else if(a=='R') nc++;\n            else if(a=='P'||a=='Q'||a=='.') {}\n            else return false;\n\n            if(nr<0||nr>=N||nc<0||nc>=N) return false;\n\n            if((a=='U'||a=='D'||a=='L'||a=='R') && !cr.large && cr.holding){\n                if(grid[nr][nc]!=-1) return false;\n            }\n            if(a=='P'){\n                if(cr.holding) return false;\n                if(grid[r][c]==-1) return false;\n            }\n            if(a=='Q'){\n                if(!cr.holding) return false;\n                if(grid[r][c]!=-1) return false;\n            }\n            mv[k]={r,c,nr,nc};\n        }\n\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                if(mv[i].dr==mv[j].dr && mv[i].dc==mv[j].dc) return false;\n            }\n        }\n        for(int i=0;i<N;i++){\n            if(!cranes[i].alive || willBomb[i]) continue;\n            for(int j=i+1;j<N;j++){\n                if(!cranes[j].alive || willBomb[j]) continue;\n                bool sw = (mv[i].dr==mv[j].sr && mv[i].dc==mv[j].sc &&\n                           mv[j].dr==mv[i].sr && mv[j].dc==mv[i].sc &&\n                           !(mv[i].sr==mv[j].sr && mv[i].sc==mv[j].sc));\n                if(sw) return false;\n            }\n        }\n        return true;\n    }\n\n    void applyActions(const array<char,N>& act){\n        array<bool,N> willBomb{};\n        array<int,N> nr,nc;\n        for(int k=0;k<N;k++){\n            willBomb[k]=false;\n            nr[k]=cranes[k].r;\n            nc[k]=cranes[k].c;\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            if(a=='B'){ willBomb[k]=true; continue; }\n            if(a=='U') nr[k]--;\n            else if(a=='D') nr[k]++;\n            else if(a=='L') nc[k]--;\n            else if(a=='R') nc[k]++;\n        }\n\n        for(int k=0;k<N;k++){\n            if(cranes[k].alive && willBomb[k]) cranes[k].alive=false;\n        }\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            if(act[k]=='B') continue;\n            cranes[k].r=nr[k];\n            cranes[k].c=nc[k];\n        }\n        for(int k=0;k<N;k++){\n            if(!cranes[k].alive) continue;\n            char a=act[k];\n            int r=cranes[k].r, c=cranes[k].c;\n            if(a=='P'){\n                int id=grid[r][c];\n                grid[r][c]=-1;\n                posR[id]=posC[id]=-1;\n                cranes[k].holding=true;\n                cranes[k].held=id;\n            } else if(a=='Q'){\n                int id=cranes[k].held;\n                grid[r][c]=id;\n                posR[id]=r; posC[id]=c;\n                cranes[k].holding=false;\n                cranes[k].held=-1;\n            }\n        }\n        for(int r=0;r<N;r++){\n            int id=grid[r][4];\n            if(id==-1) continue;\n            grid[r][4]=-1;\n            posR[id]=posC[id]=-1;\n            int t=id/N, idx=id%N;\n            if(((dispMask[t]>>idx)&1)==0){\n                dispMask[t] |= (1<<idx);\n                dispatchedCount++;\n            }\n        }\n    }\n\n    // ===== run =====\n    void run(){\n        while(turn < MAX_TURNS && dispatchedCount < N*N){\n            int before = dispatchedCount;\n\n            spawnPhase();\n\n            if(mode==0){\n                if(noDispatchTurns >= STUCK_LIMIT || turn >= LATE_LIMIT){\n                    mode = 1;\n                    plan0.clear();\n                } else if(countEmptyStrictStorageParallel()<=0 && chooseBestExpectedOnGrid(true)==-1){\n                    mode = 1;\n                    plan0.clear();\n                }\n            }\n            if(mode==1){\n                bool anyAlive=false;\n                for(int i=1;i<N;i++) if(cranes[i].alive) anyAlive=true;\n                if(!anyAlive){\n                    mode = 2;\n                    plan0.clear();\n                }\n            }\n\n            if(plan0.empty()){\n                if(mode==0) buildLargePlanParallel();\n                else buildLargePlanSolo();\n            }\n\n            array<char,N> act; act.fill('.');\n            act[0] = plan0.empty()?'.':plan0.front();\n\n            // lock row if large is/will be on (row>0,col=1)\n            int lockRow=-1;\n            if(cranes[0].alive){\n                int lr=cranes[0].r, lc=cranes[0].c;\n                int dr=lr, dc=lc;\n                if(act[0]=='U') dr--;\n                else if(act[0]=='D') dr++;\n                else if(act[0]=='L') dc--;\n                else if(act[0]=='R') dc++;\n                if(dr>0 && dc==1) lockRow=dr;\n                if(lr>0 && lc==1 && (act[0]=='.' || act[0]=='P' || act[0]=='Q')) lockRow=lr;\n            }\n\n            for(int i=1;i<N;i++){\n                act[i] = (mode==0 ? decideSmallParallel(i, lockRow) : decideSmallBomb(i));\n            }\n\n            if(!validateActions(act)){\n                array<char,N> a1=act;\n                a1[0]='.';\n                if(validateActions(a1)){\n                    act=a1;\n                    plan0.clear();\n                } else {\n                    array<char,N> a2=act;\n                    for(int i=1;i<N;i++) a2[i]='.';\n                    if(validateActions(a2)){\n                        act=a2;\n                    } else {\n                        array<char,N> a3; a3.fill('.');\n                        act=a3;\n                        plan0.clear();\n                    }\n                }\n            }\n\n            if(!plan0.empty() && act[0]==plan0.front()){\n                plan0.pop_front();\n            } else if(act[0] != '.'){\n                plan0.clear();\n            }\n\n            for(int i=0;i<N;i++) out[i].push_back(act[i]);\n\n            applyActions(act);\n\n            if(dispatchedCount == before) noDispatchTurns++;\n            else noDispatchTurns = 0;\n\n            turn++;\n        }\n\n        if(turn==0){\n            for(int i=0;i<N;i++) out[i].push_back('.');\n        }\n    }\n\n    void print() const {\n        for(int i=0;i<N;i++) cout << out[i] << \"\\n\";\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<vector<int>> Ain(n, vector<int>(n));\n    for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin >> Ain[i][j];\n\n    Solver solver(Ain);\n    solver.run();\n    solver.print();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF = (1LL<<62);\n\nstatic inline int id(int r, int c, int N){ return r*N + c; }\nstatic inline int r_of(int v, int N){ return v / N; }\nstatic inline int c_of(int v, int N){ return v % N; }\n\nstatic inline char move_dir(int from, int to, int N){\n    int fr = r_of(from, N), fc = c_of(from, N);\n    int tr = r_of(to, N), tc = c_of(to, N);\n    if (tr == fr-1 && tc == fc) return 'U';\n    if (tr == fr+1 && tc == fc) return 'D';\n    if (tr == fr && tc == fc-1) return 'L';\n    if (tr == fr && tc == fc+1) return 'R';\n    return '?';\n}\n\nstruct Emitter {\n    vector<string> ops;\n    void emit_move(char c) { ops.emplace_back(1, c); }\n    void emit_amount(char sign, long long d) {\n        while (d > 0) {\n            long long x = min(d, 1000000LL);\n            ops.push_back(string(1, sign) + to_string(x));\n            d -= x;\n        }\n    }\n};\n\n// splitmix64 RNG\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    inline uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    inline int next_int(int l, int r){ // inclusive\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    inline double next_double01(){\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\n// perms for k<=4\nstatic array<vector<array<int,4>>, 5> PERMS;\nstatic void init_perms(){\n    for(int k=0;k<=4;k++){\n        vector<int> v(k);\n        iota(v.begin(), v.end(), 0);\n        do{\n            array<int,4> p{};\n            for(int i=0;i<k;i++) p[i]=v[i];\n            PERMS[k].push_back(p);\n        }while(next_permutation(v.begin(), v.end()));\n    }\n}\n\nstatic inline bool would_create_cycle(const vector<int>& parent, int u, int newp){\n    int x = newp;\n    while(x != -1){\n        if(x == u) return true;\n        x = parent[x];\n    }\n    return false;\n}\n\nstruct Plan {\n    long long cost = INF;\n    array<array<int,4>, 400> order{};\n    array<uint8_t, 400> deg{};\n    array<long long, 400> need{};\n    vector<int> parent;\n};\n\nstruct TreeEvaluator {\n    int N, V;\n    const vector<int> *h;\n\n    array<array<int,4>, 400> child{};\n    array<uint8_t, 400> deg{};\n    array<uint8_t, 400> it{};\n    array<int, 400> st{};\n    array<int, 400> post{};\n    array<long long, 400> subsum{}, need{}, out{}, dp{};\n\n    TreeEvaluator(int N, const vector<int>& h): N(N), V(N*N), h(&h) {}\n\n    long long eval_cost(const vector<int>& parent){\n        for(int i=0;i<V;i++) deg[i]=0;\n        for(int v=1; v<V; v++){\n            int p = parent[v];\n            if(p < 0) return INF;\n            if(deg[p] >= 4) return INF;\n            child[p][deg[p]++] = v;\n        }\n\n        for(int i=0;i<V;i++) it[i]=0;\n        int top=0, ptop=0;\n        st[top++] = 0;\n        while(top){\n            int v = st[top-1];\n            if(it[v] < deg[v]){\n                int c = child[v][it[v]++];\n                st[top++] = c;\n            }else{\n                post[ptop++] = v;\n                top--;\n            }\n        }\n        if(ptop != V) return INF;\n\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            long long s = (*h)[v];\n            for(int i=0;i<deg[v];i++) s += subsum[child[v][i]];\n            subsum[v] = s;\n        }\n        if(subsum[0] != 0) return INF;\n\n        for(int v=0; v<V; v++){\n            need[v] = max(0LL, -subsum[v]);\n            out[v]  = max(0LL,  subsum[v]);\n        }\n\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            int k = deg[v];\n\n            long long base = 0;\n            for(int i=0;i<k;i++){\n                int c = child[v][i];\n                long long dc = dp[c];\n                if(dc >= INF/4){ base = INF; break; }\n                base += dc;\n                base += 200 + need[c] + out[c];\n                if(base >= INF/4){ base = INF; break; }\n            }\n            if(base >= INF/4){ dp[v] = INF; continue; }\n\n            long long best = INF;\n\n            if(k == 0){\n                long long curH = (*h)[v];\n                long long load = need[v];\n                long long cost = 0;\n                if(curH > 0){ cost += curH; load += curH; }\n                else if(curH < 0){\n                    long long x = -curH;\n                    cost += x; load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n                dp[v] = cost;\n                continue;\n            }\n\n            int kids[4];\n            for(int i=0;i<k;i++) kids[i] = child[v][i];\n\n            for(const auto &perm : PERMS[k]){\n                long long curH = (*h)[v];\n                long long load = need[v];\n                long long cost = base;\n\n                for(int j=0;j<k;j++){\n                    int c = kids[perm[j]];\n                    long long target = need[c];\n                    if(load < target){\n                        long long d = target - load;\n                        cost += d; curH -= d; load = target;\n                    }else if(load > target){\n                        long long d = load - target;\n                        cost += d; curH += d; load = target;\n                    }\n                    load = out[c];\n                }\n\n                if(curH > 0){\n                    cost += curH; load += curH;\n                }else if(curH < 0){\n                    long long x = -curH;\n                    cost += x; load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n\n                if(cost < best) best = cost;\n            }\n\n            dp[v] = best;\n        }\n\n        return dp[0];\n    }\n\n    Plan build_plan(const vector<int>& parent){\n        Plan plan;\n        plan.parent = parent;\n\n        for(int i=0;i<V;i++) deg[i]=0;\n        for(int v=1; v<V; v++){\n            int p = parent[v];\n            child[p][deg[p]++] = v;\n        }\n\n        for(int i=0;i<V;i++) it[i]=0;\n        int top=0, ptop=0;\n        st[top++] = 0;\n        while(top){\n            int v = st[top-1];\n            if(it[v] < deg[v]){\n                int c = child[v][it[v]++];\n                st[top++] = c;\n            }else{\n                post[ptop++] = v;\n                top--;\n            }\n        }\n\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            long long s = (*h)[v];\n            for(int i=0;i<deg[v];i++) s += subsum[child[v][i]];\n            subsum[v] = s;\n        }\n\n        for(int v=0; v<V; v++){\n            plan.need[v] = max(0LL, -subsum[v]);\n            out[v]       = max(0LL,  subsum[v]);\n            plan.deg[v]  = deg[v];\n        }\n\n        for(int idx=0; idx<V; idx++){\n            int v = post[idx];\n            int k = deg[v];\n\n            long long base = 0;\n            for(int i=0;i<k;i++){\n                int c = child[v][i];\n                base += dp[c];\n                base += 200 + plan.need[c] + out[c];\n            }\n\n            long long best = INF;\n            array<int,4> bestOrd{};\n\n            if(k == 0){\n                best = llabs((long long)(*h)[v]);\n                plan.order[v] = bestOrd;\n                dp[v] = best;\n                continue;\n            }\n\n            int kids[4];\n            for(int i=0;i<k;i++) kids[i] = child[v][i];\n\n            for(const auto &perm : PERMS[k]){\n                long long curH = (*h)[v];\n                long long load = plan.need[v];\n                long long cost = base;\n\n                for(int j=0;j<k;j++){\n                    int c = kids[perm[j]];\n                    long long target = plan.need[c];\n                    if(load < target){\n                        long long d = target - load;\n                        cost += d; curH -= d; load = target;\n                    }else if(load > target){\n                        long long d = load - target;\n                        cost += d; curH += d; load = target;\n                    }\n                    load = out[c];\n                }\n\n                if(curH > 0){\n                    cost += curH; load += curH;\n                }else if(curH < 0){\n                    long long x = -curH;\n                    cost += x; load -= x;\n                    if(load < 0) cost = INF;\n                }\n                if(cost < INF && load != out[v]) cost = INF;\n\n                if(cost < best){\n                    best = cost;\n                    for(int j=0;j<k;j++) bestOrd[j] = kids[perm[j]];\n                }\n            }\n\n            plan.order[v] = bestOrd;\n            dp[v] = best;\n        }\n\n        plan.cost = dp[0];\n        return plan;\n    }\n};\n\nstatic void build_ops_from_plan(const Plan& plan, const vector<int>& h, int N, vector<string>& out_ops){\n    int V = N*N;\n    vector<long long> curH(V);\n    for(int i=0;i<V;i++) curH[i] = h[i];\n\n    Emitter em;\n    long long load = 0;\n\n    struct Frame{ int v; int idx; };\n    array<Frame, 410> st;\n    int sp=0;\n    st[sp++] = {0,0};\n\n    while(sp){\n        int v = st[sp-1].v;\n        int &idx = st[sp-1].idx;\n        int k = plan.deg[v];\n\n        if(idx < k){\n            int c = plan.order[v][idx++];\n            long long target = plan.need[c];\n\n            if(load < target){\n                long long d = target - load;\n                em.emit_amount('+', d);\n                curH[v] -= d;\n                load = target;\n            }else if(load > target){\n                long long d = load - target;\n                em.emit_amount('-', d);\n                curH[v] += d;\n                load = target;\n            }\n\n            char mv = move_dir(v, c, N);\n            if(mv == '?'){ out_ops.clear(); return; }\n            em.emit_move(mv);\n            st[sp++] = {c,0};\n        }else{\n            if(curH[v] > 0){\n                long long x = curH[v];\n                em.emit_amount('+', x);\n                load += x;\n                curH[v] = 0;\n            }else if(curH[v] < 0){\n                long long x = -curH[v];\n                em.emit_amount('-', x);\n                load -= x;\n                curH[v] = 0;\n            }\n\n            sp--;\n            if(sp==0) break;\n            int p = st[sp-1].v;\n            char mv = move_dir(v, p, N);\n            if(mv == '?'){ out_ops.clear(); return; }\n            em.emit_move(mv);\n        }\n    }\n\n    out_ops = std::move(em.ops);\n}\n\n// --- initial tree generators ---\nstatic vector<int> bfs_tree(int N, const array<int,4>& ord){\n    int V = N*N;\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        int r=r_of(v,N), c=c_of(v,N);\n        for(int t: ord){\n            int nr=r, nc=c;\n            if(t==0) nr--;\n            if(t==1) nr++;\n            if(t==2) nc--;\n            if(t==3) nc++;\n            if(nr<0||nr>=N||nc<0||nc>=N) continue;\n            int u=id(nr,nc,N);\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstruct DSU{\n    int n;\n    vector<int> p, r;\n    DSU(int n=0):n(n),p(n),r(n,0){ iota(p.begin(),p.end(),0); }\n    int find(int a){ while(p[a]!=a){ p[a]=p[p[a]]; a=p[a]; } return a; }\n    bool unite(int a,int b){\n        a=find(a); b=find(b);\n        if(a==b) return false;\n        if(r[a]<r[b]) swap(a,b);\n        p[b]=a;\n        if(r[a]==r[b]) r[a]++;\n        return true;\n    }\n};\n\nstatic vector<int> random_kruskal_tree(int V, const vector<pair<int,int>>& edges, SplitMix64& rng){\n    vector<pair<int,int>> e = edges;\n    for(int i=(int)e.size()-1;i>0;i--){\n        int j = (int)(rng.next_u64() % (uint64_t)(i+1));\n        swap(e[i], e[j]);\n    }\n    DSU dsu(V);\n    vector<vector<int>> g(V);\n    g.assign(V, {});\n    int used=0;\n    for(auto [a,b]: e){\n        if(dsu.unite(a,b)){\n            g[a].push_back(b);\n            g[b].push_back(a);\n            if(++used == V-1) break;\n        }\n    }\n    vector<int> parent(V, -1);\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(0);\n    vis[0]=1;\n    while(!q.empty()){\n        int v=q.front(); q.pop();\n        for(int u: g[v]){\n            if(!vis[u]){\n                vis[u]=1;\n                parent[u]=v;\n                q.push(u);\n            }\n        }\n    }\n    return parent;\n}\n\nstatic vector<int> biased_prim_tree(int N, const vector<int>& h, SplitMix64& rng){\n    int V = N*N;\n    vector<char> in(V, 0);\n    vector<int> parent(V, -1);\n\n    vector<int> pos(V, -1);\n    vector<int> frontier;\n    frontier.reserve(V);\n    vector<array<int,4>> candP(V);\n    vector<uint8_t> ccnt(V, 0);\n\n    auto add_front = [&](int u, int p){\n        if(in[u]) return;\n        if(pos[u] == -1){\n            pos[u] = (int)frontier.size();\n            frontier.push_back(u);\n        }\n        if(ccnt[u] < 4) candP[u][ccnt[u]++] = p;\n    };\n    auto pop_front = [&](int u){\n        int i = pos[u];\n        int last = frontier.back();\n        frontier[i] = last;\n        pos[last] = i;\n        frontier.pop_back();\n        pos[u] = -1;\n    };\n    auto try_add_neighbors = [&](int v){\n        int r=r_of(v,N), c=c_of(v,N);\n        if(r>0) add_front(id(r-1,c,N), v);\n        if(r+1<N) add_front(id(r+1,c,N), v);\n        if(c>0) add_front(id(r,c-1,N), v);\n        if(c+1<N) add_front(id(r,c+1,N), v);\n    };\n\n    in[0]=1;\n    try_add_neighbors(0);\n\n    int added=1;\n    while(added < V){\n        int u = frontier[rng.next_int(0, (int)frontier.size()-1)];\n\n        long long tot=0;\n        long long w[4];\n        for(int i=0;i<ccnt[u];i++){\n            int p = candP[u][i];\n            long long ww = 1;\n            if(h[u]!=0 && h[p]!=0 && (long long)h[u]*h[p] < 0) ww += 7;\n            ww += (abs(h[u]) + abs(h[p]) >= 120 ? 2 : 0);\n            w[i]=ww; tot += ww;\n        }\n        long long x = (long long)(rng.next_u64() % (uint64_t)tot) + 1;\n        int psel = candP[u][0];\n        for(int i=0;i<ccnt[u];i++){\n            x -= w[i];\n            if(x <= 0){ psel = candP[u][i]; break; }\n        }\n\n        parent[u] = psel;\n        in[u]=1;\n        added++;\n\n        pop_front(u);\n        ccnt[u]=0;\n        try_add_neighbors(u);\n    }\n    return parent;\n}\n\n// fixed-size adjacency remove\nstatic inline void adj_remove(array<int,4>& a, uint8_t& d, int x){\n    for(uint8_t i=0;i<d;i++){\n        if(a[i]==x){\n            a[i] = a[d-1];\n            d--;\n            return;\n        }\n    }\n}\n\n// generate up to 3 exchange candidates (grid-safe), each as a rooted parent[]\nstatic int gen_exchange_candidates(\n    const vector<int>& parent,\n    const array<long long,400>& subsum,\n    const array<array<int,4>,400>& gridAdj,\n    const array<uint8_t,400>& gridDeg,\n    SplitMix64& rng,\n    int N,\n    array<vector<int>,3>& candParent\n){\n    const int V = N*N;\n\n    // choose x with bias by |subsum|\n    int x = rng.next_int(1, V-1);\n    for(int t=0;t<2;t++){\n        int z = rng.next_int(1, V-1);\n        if(llabs(subsum[z]) > llabs(subsum[x])) x = z;\n    }\n\n    // choose y among grid neighbors that's not a tree edge\n    int y = -1;\n    long long bestS = LLONG_MIN;\n    for(uint8_t i=0;i<gridDeg[x];i++){\n        int c = gridAdj[x][i];\n        if(parent[x]==c || parent[c]==x) continue;\n        long long sc = 0;\n        if(subsum[x]!=0 && subsum[c]!=0 && subsum[x]*subsum[c] < 0) sc += 5;\n        sc += (rng.next_u64() & 1);\n        if(sc > bestS){ bestS = sc; y = c; }\n    }\n    if(y < 0) return 0;\n\n    // build tree adjacency\n    array<array<int,4>,400> tadj;\n    array<uint8_t,400> tdeg;\n    for(int i=0;i<V;i++) tdeg[i]=0;\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        if(p < 0) return 0;\n        if(tdeg[v] >= 4 || tdeg[p] >= 4) return 0;\n        tadj[v][tdeg[v]++] = p;\n        tadj[p][tdeg[p]++] = v;\n    }\n\n    // BFS path x->y in tree\n    array<int,400> prev;\n    for(int i=0;i<V;i++) prev[i] = -1;\n    queue<int> q;\n    prev[x] = x;\n    q.push(x);\n    while(!q.empty() && prev[y] == -1){\n        int v=q.front(); q.pop();\n        for(uint8_t i=0;i<tdeg[v];i++){\n            int to = tadj[v][i];\n            if(prev[to] != -1) continue;\n            prev[to] = v;\n            q.push(to);\n        }\n    }\n    if(prev[y] == -1) return 0;\n\n    vector<int> path;\n    for(int cur=y;;cur=prev[cur]){\n        path.push_back(cur);\n        if(cur==x) break;\n    }\n    reverse(path.begin(), path.end());\n    int L = (int)path.size();\n    if(L < 2) return 0;\n\n    // candidate cut edges on path: random, middle, max |subsum| internal\n    int e0 = rng.next_int(0, L-2);\n    int e1 = (L-2)/2;\n    int e2 = e0;\n    long long bestAbs = -1;\n    for(int i=1;i<L-1;i++){\n        long long aabs = llabs(subsum[path[i]]);\n        if(aabs > bestAbs){\n            bestAbs = aabs;\n            e2 = i-1;\n        }\n    }\n    int candE[3] = {e0,e1,e2};\n    sort(candE, candE+3);\n    for(int i=1;i<3;i++) if(candE[i]==candE[i-1]) candE[i] = -1;\n\n    auto build_one = [&](int ei, vector<int>& outp)->bool{\n        if(ei < 0) return false;\n\n        // copy adjacency\n        array<array<int,4>,400> g = tadj;\n        array<uint8_t,400> gd = tdeg;\n\n        int a = path[ei], b = path[ei+1];\n        adj_remove(g[a], gd[a], b);\n        adj_remove(g[b], gd[b], a);\n\n        if(gd[x] >= 4 || gd[y] >= 4) return false;\n        g[x][gd[x]++] = y;\n        g[y][gd[y]++] = x;\n\n        outp.assign(V, -2);\n        queue<int> qq;\n        outp[0] = -1;\n        qq.push(0);\n        while(!qq.empty()){\n            int v=qq.front(); qq.pop();\n            for(uint8_t i=0;i<gd[v];i++){\n                int to = g[v][i];\n                if(outp[to] != -2) continue;\n                outp[to] = v;\n                qq.push(to);\n            }\n        }\n        for(int i=0;i<V;i++) if(outp[i]==-2) return false;\n        return true;\n    };\n\n    int cnt = 0;\n    for(int i=0;i<3;i++){\n        if(build_one(candE[i], candParent[cnt])){\n            cnt++;\n            if(cnt==3) break;\n        }\n    }\n    return cnt;\n}\n\nstatic inline void compute_childcnt(\n    const vector<int>& parent,\n    array<uint8_t,400>& childCnt\n){\n    int V = (int)parent.size();\n    for(int i=0;i<V;i++) childCnt[i]=0;\n    for(int v=1; v<V; v++){\n        int p = parent[v];\n        if(p>=0) childCnt[p]++;\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_perms();\n\n    int N;\n    cin >> N;\n    const int V = N*N;\n    vector<int> h(V);\n    for(int i=0;i<N;i++) for(int j=0;j<N;j++) cin >> h[id(i,j,N)];\n\n    // grid adjacency\n    array<array<int,4>, 400> gridAdj{};\n    array<uint8_t, 400> gridDeg{};\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v=id(r,c,N);\n            uint8_t k=0;\n            if(r>0) gridAdj[v][k++] = id(r-1,c,N);\n            if(r+1<N) gridAdj[v][k++] = id(r+1,c,N);\n            if(c>0) gridAdj[v][k++] = id(r,c-1,N);\n            if(c+1<N) gridAdj[v][k++] = id(r,c+1,N);\n            gridDeg[v]=k;\n        }\n    }\n\n    // edges for Kruskal\n    vector<pair<int,int>> edges;\n    edges.reserve(2*N*(N-1));\n    for(int r=0;r<N;r++){\n        for(int c=0;c<N;c++){\n            int v=id(r,c,N);\n            if(r+1<N) edges.push_back({v, id(r+1,c,N)});\n            if(c+1<N) edges.push_back({v, id(r,c+1,N)});\n        }\n    }\n\n    uint64_t seed = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    SplitMix64 rng(seed);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    const double TL = 1.88; // safe margin\n\n    TreeEvaluator eval(N, h);\n\n    vector<int> best_parent;\n    long long best_cost = INF;\n    array<long long,400> best_subsum{};\n    array<uint8_t,400> best_childCnt{};\n\n    auto consider = [&](const vector<int>& parent){\n        long long c = eval.eval_cost(parent);\n        if(c < best_cost){\n            best_cost = c;\n            best_parent = parent;\n            best_subsum = eval.subsum;\n            compute_childcnt(best_parent, best_childCnt);\n        }\n    };\n\n    // initial pool\n    {\n        array<array<int,4>,4> orders = {{\n            {3,1,2,0}, {1,3,2,0}, {3,2,1,0}, {1,2,3,0}\n        }};\n        for(auto ord: orders) consider(bfs_tree(N, ord));\n        for(int i=0;i<14;i++) consider(random_kruskal_tree(V, edges, rng));\n        for(int i=0;i<70;i++) consider(biased_prim_tree(N, h, rng));\n    }\n    if(best_parent.empty()){\n        best_parent = bfs_tree(N, {3,1,2,0});\n        best_cost = eval.eval_cost(best_parent);\n        best_subsum = eval.subsum;\n        compute_childcnt(best_parent, best_childCnt);\n    }\n\n    vector<int> cur_parent = best_parent;\n    long long cur_cost = best_cost;\n    array<long long,400> cur_subsum = best_subsum;\n    array<uint8_t,400> cur_childCnt = best_childCnt;\n\n    array<vector<int>,3> exchCand;\n    for(int i=0;i<3;i++) exchCand[i].reserve(V);\n    array<array<long long,400>,3> candSubsum;\n    array<long long,3> candCost{};\n\n    long long iter = 0;\n    double now = elapsed();\n\n    while(now < TL){\n        iter++;\n        if((iter & 4095) == 0) now = elapsed();\n\n        double t = min(1.0, now / TL);\n        double T0 = 2200.0, T1 = 12.0;\n        double temp = T0 * pow(T1 / T0, t);\n        double invTemp = 1.0 / temp;\n\n        if((iter % 15000) == 0){\n            cur_parent = best_parent;\n            cur_cost = best_cost;\n            cur_subsum = best_subsum;\n            cur_childCnt = best_childCnt;\n        }\n\n        // exchange move (rare); evaluate best-of-K candidates by real cost\n        bool do_exchange = ((rng.next_u64() % 17ull) == 0ull) && (now + 0.07 < TL); // ~5.9%\n        if(do_exchange){\n            int cnt = gen_exchange_candidates(cur_parent, cur_subsum, gridAdj, gridDeg, rng, N, exchCand);\n            if(cnt == 0) continue;\n\n            int besti = -1;\n            long long bestc = INF;\n            for(int i=0;i<cnt;i++){\n                long long c = eval.eval_cost(exchCand[i]);\n                if(c >= INF/2) continue;\n                candCost[i] = c;\n                candSubsum[i] = eval.subsum;\n                if(c < bestc){\n                    bestc = c;\n                    besti = i;\n                }\n            }\n            if(besti < 0) continue;\n\n            bool accept = false;\n            if(bestc <= cur_cost) accept = true;\n            else{\n                long long d = bestc - cur_cost;\n                double x = (double)d * invTemp;\n                if(x < 60.0 && rng.next_double01() < exp(-x)) accept = true;\n            }\n            if(accept){\n                cur_parent = exchCand[besti];\n                cur_cost = bestc;\n                cur_subsum = candSubsum[besti];\n                compute_childcnt(cur_parent, cur_childCnt);\n\n                if(cur_cost < best_cost){\n                    best_cost = cur_cost;\n                    best_parent = cur_parent;\n                    best_subsum = cur_subsum;\n                    best_childCnt = cur_childCnt;\n                }\n            }\n            continue;\n        }\n\n        // normal reparent move (grid-adjacent), with fast capacity pruning\n        int u;\n        if((rng.next_u64() & 7ull) == 0ull){\n            u = rng.next_int(1, V-1);\n        }else{\n            int u1 = rng.next_int(1, V-1);\n            int u2 = rng.next_int(1, V-1);\n            int u3 = rng.next_int(1, V-1);\n            u = u1;\n            if(llabs(cur_subsum[u2]) > llabs(cur_subsum[u])) u = u2;\n            if(llabs(cur_subsum[u3]) > llabs(cur_subsum[u])) u = u3;\n        }\n\n        int oldp = cur_parent[u];\n        int k = gridDeg[u];\n\n        int newp = -1;\n        long long bestS = LLONG_MIN;\n        for(int tries=0; tries<4; tries++){\n            int p = gridAdj[u][rng.next_int(0, k-1)];\n            if(p == oldp) continue;\n            if(would_create_cycle(cur_parent, u, p)) continue;\n\n            // capacity: max children = gridDeg[p] - (p!=0)\n            int maxChildren = (int)gridDeg[p] - (p!=0 ? 1 : 0);\n            if((int)cur_childCnt[p] >= maxChildren) continue;\n\n            long long sc = 0;\n            if(cur_subsum[u] != 0 && cur_subsum[p] != 0 && cur_subsum[u]*cur_subsum[p] < 0) sc += 4;\n            if(cur_subsum[u] != 0 && h[p] != 0 && cur_subsum[u]*(long long)h[p] < 0) sc += 2;\n            sc += (abs(h[p]) >= 60 ? 1 : 0);\n            sc += (int)(rng.next_u64() & 1);\n\n            if(sc > bestS){\n                bestS = sc;\n                newp = p;\n            }\n        }\n        if(newp == -1) continue;\n\n        // apply\n        cur_parent[u] = newp;\n        long long nxt_cost = eval.eval_cost(cur_parent);\n        if(nxt_cost >= INF/2){\n            cur_parent[u] = oldp;\n            continue;\n        }\n\n        bool accept = false;\n        if(nxt_cost <= cur_cost) accept = true;\n        else{\n            long long d = nxt_cost - cur_cost;\n            double x = (double)d * invTemp;\n            if(x < 60.0 && rng.next_double01() < exp(-x)) accept = true;\n        }\n\n        if(accept){\n            // update counts\n            cur_childCnt[oldp]--;\n            cur_childCnt[newp]++;\n            cur_cost = nxt_cost;\n            cur_subsum = eval.subsum;\n\n            if(cur_cost < best_cost){\n                best_cost = cur_cost;\n                best_parent = cur_parent;\n                best_subsum = cur_subsum;\n                best_childCnt = cur_childCnt;\n            }\n        }else{\n            cur_parent[u] = oldp;\n        }\n    }\n\n    Plan plan = eval.build_plan(best_parent);\n    vector<string> ops;\n    build_ops_from_plan(plan, h, N, ops);\n\n    if((int)ops.size() > 100000) ops.clear();\n    for(auto &s: ops) cout << s << \"\\n\";\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ull;\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() { // [0,1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n};\n\nstatic constexpr int MMAX = 15;\n\nstruct Seed {\n    array<uint8_t, MMAX> x{};\n    int V = 0;\n    int peak = 0;\n};\n\nstatic inline int diffCount(const Seed& a, const Seed& b, int M) {\n    int d = 0;\n    for (int i = 0; i < M; i++) d += (a.x[i] != b.x[i]);\n    return d;\n}\nstatic inline int sumAbsDiff(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += abs((int)a.x[i] - (int)b.x[i]);\n    return s;\n}\nstatic inline int potentialSumMax(const Seed& a, const Seed& b, int M) {\n    int s = 0;\n    for (int i = 0; i < M; i++) s += max<int>(a.x[i], b.x[i]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    using Clock = chrono::steady_clock;\n    using TimePoint = Clock::time_point;\n\n    int N, M, T;\n    cin >> N >> M >> T;\n    const int SEED_COUNT = 2 * N * (N - 1); // 60\n    const int P = N * N;                    // 36\n\n    vector<Seed> seeds(SEED_COUNT);\n\n    auto readSeeds = [&]() {\n        for (int k = 0; k < SEED_COUNT; k++) {\n            int sum = 0, pk = 0;\n            for (int l = 0; l < M; l++) {\n                int v;\n                cin >> v;\n                seeds[k].x[l] = (uint8_t)v;\n                sum += v;\n                pk = max(pk, v);\n            }\n            seeds[k].V = sum;\n            seeds[k].peak = pk;\n        }\n    };\n\n    readSeeds();\n\n    // Grid neighbors and edges\n    vector<vector<int>> neigh(P);\n    vector<pair<int,int>> edges;\n    vector<int> degree(P, 0);\n    auto id = [&](int i, int j) { return i * N + j; };\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int v = id(i, j);\n            if (i > 0) neigh[v].push_back(id(i - 1, j));\n            if (i + 1 < N) neigh[v].push_back(id(i + 1, j));\n            if (j > 0) neigh[v].push_back(id(i, j - 1));\n            if (j + 1 < N) neigh[v].push_back(id(i, j + 1));\n            degree[v] = (int)neigh[v].size();\n        }\n    }\n    for (int i = 0; i < N; i++)\n        for (int j = 0; j + 1 < N; j++)\n            edges.push_back({id(i, j), id(i, j + 1)});\n    for (int i = 0; i + 1 < N; i++)\n        for (int j = 0; j < N; j++)\n            edges.push_back({id(i, j), id(i + 1, j)});\n\n    vector<int> posOrder(P);\n    iota(posOrder.begin(), posOrder.end(), 0);\n    sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n        if (degree[a] != degree[b]) return degree[a] > degree[b];\n        return a < b;\n    });\n\n    vector<int> centers;\n    for (int p = 0; p < P; p++) if (degree[p] == 4) centers.push_back(p);\n\n    RNG rng;\n    TimePoint globalStart = Clock::now();\n    const double TIME_LIMIT = 1.90;\n\n    auto evalObjective = [&](const vector<int>& perm,\n                             const vector<vector<double>>& w,\n                             const vector<int>& impLocal,\n                             double alphaUnary) -> double {\n        double s = 0.0;\n        for (auto [u, v] : edges) s += w[perm[u]][perm[v]];\n        if (alphaUnary > 0) {\n            for (int pos = 0; pos < P; pos++) s += alphaUnary * (double)degree[pos] * (double)impLocal[perm[pos]];\n        }\n        return s;\n    };\n\n    auto runSA = [&](vector<int> perm,\n                     const vector<vector<double>>& w,\n                     const vector<int>& impLocal,\n                     double alphaUnary,\n                     TimePoint endTime) -> pair<double, vector<int>> {\n        double cur = evalObjective(perm, w, impLocal, alphaUnary);\n        double best = cur;\n        vector<int> bestPerm = perm;\n\n        const double tempStart = 520.0;\n        const double tempEnd = 12.0;\n\n        TimePoint t0 = Clock::now();\n        double total = chrono::duration<double>(endTime - t0).count();\n        if (total <= 1e-9) return {cur, perm};\n\n        while (Clock::now() < endTime) {\n            int a = rng.nextInt(P);\n            int b = rng.nextInt(P);\n            if (a == b) continue;\n\n            int la = perm[a];\n            int lb = perm[b];\n\n            double delta = 0.0;\n            // edge deltas\n            for (int na : neigh[a]) {\n                if (na == b) continue;\n                int lx = perm[na];\n                delta += w[lb][lx] - w[la][lx];\n            }\n            for (int nb : neigh[b]) {\n                if (nb == a) continue;\n                int lx = perm[nb];\n                delta += w[la][lx] - w[lb][lx];\n            }\n\n            // unary delta\n            if (alphaUnary > 0) {\n                double da = alphaUnary * (double)degree[a];\n                double db = alphaUnary * (double)degree[b];\n                delta += da * ((double)impLocal[lb] - (double)impLocal[la])\n                      +  db * ((double)impLocal[la] - (double)impLocal[lb]);\n            }\n\n            double prog = chrono::duration<double>(Clock::now() - t0).count() / total;\n            prog = min(1.0, max(0.0, prog));\n            double temp = tempStart * pow(tempEnd / tempStart, prog);\n\n            bool accept = (delta >= 0.0) || (rng.nextDouble() < exp(delta / temp));\n            if (accept) {\n                swap(perm[a], perm[b]);\n                cur += delta;\n                if (cur > best) {\n                    best = cur;\n                    bestPerm = perm;\n                }\n            }\n        }\n        return {best, bestPerm};\n    };\n\n    for (int t = 0; t < T; t++) {\n        // per-turn budget\n        double elapsed = chrono::duration<double>(Clock::now() - globalStart).count();\n        double remaining = max(0.0, TIME_LIMIT - elapsed);\n        double perTurn = remaining / max(1, (T - t));\n        TimePoint turnStart = Clock::now();\n        TimePoint turnEnd = turnStart + chrono::duration_cast<Clock::duration>(chrono::duration<double>(perTurn * 0.97));\n\n        double phase = (T == 1) ? 1.0 : (double)t / (double)(T - 1);\n\n        // ---- Selection (revert to stable, high-V focused) ----\n        vector<int> idx(SEED_COUNT);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (seeds[a].V != seeds[b].V) return seeds[a].V > seeds[b].V;\n            return a < b;\n        });\n\n        const int eliteCount = 10;\n        const int partnerFor = 8;\n        const int perDimTake = 1;\n\n        vector<int> selected;\n        selected.reserve(P);\n        vector<char> used(SEED_COUNT, 0), prot(SEED_COUNT, 0);\n\n        auto addSeed = [&](int k, bool protect) {\n            if (k < 0 || k >= SEED_COUNT) return;\n            if (used[k]) return;\n            used[k] = 1;\n            selected.push_back(k);\n            if (protect) prot[k] = 1;\n        };\n\n        for (int i = 0; i < eliteCount; i++) addSeed(idx[i], true);\n\n        for (int i = 0; i < partnerFor; i++) {\n            int e = idx[i];\n            int best = -1;\n            int bestScore = INT_MAX;\n            for (int j = 0; j < SEED_COUNT; j++) {\n                if (j == e || used[j]) continue;\n                int d = diffCount(seeds[e], seeds[j], M);\n                int vd = abs(seeds[e].V - seeds[j].V);\n                int score = d * 120 + vd;\n                if (score < bestScore || (score == bestScore && seeds[j].V > (best == -1 ? -1 : seeds[best].V))) {\n                    bestScore = score;\n                    best = j;\n                }\n            }\n            if (best != -1) addSeed(best, true);\n        }\n\n        for (int l = 0; l < M; l++) {\n            int best = -1;\n            for (int k = 0; k < SEED_COUNT; k++) {\n                if (used[k]) continue;\n                if (best == -1 ||\n                    seeds[k].x[l] > seeds[best].x[l] ||\n                    (seeds[k].x[l] == seeds[best].x[l] && seeds[k].V > seeds[best].V)) {\n                    best = k;\n                }\n            }\n            if (best != -1) addSeed(best, false);\n        }\n\n        auto mixedScore = [&](int k) -> int { return seeds[k].V * 10 + seeds[k].peak * 6; };\n        vector<int> rest;\n        for (int k = 0; k < SEED_COUNT; k++) if (!used[k]) rest.push_back(k);\n        sort(rest.begin(), rest.end(), [&](int a, int b) {\n            int sa = mixedScore(a), sb = mixedScore(b);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n        for (int k : rest) {\n            if ((int)selected.size() >= P) break;\n            addSeed(k, false);\n        }\n\n        if ((int)selected.size() > P) {\n            auto importance = [&](int k) -> int { return seeds[k].V * 10 + seeds[k].peak * 3; };\n            vector<int> removable;\n            for (int k : selected) if (!prot[k]) removable.push_back(k);\n            sort(removable.begin(), removable.end(), [&](int a, int b) {\n                int ia = importance(a), ib = importance(b);\n                if (ia != ib) return ia < ib;\n                return a > b;\n            });\n            int ptr = 0;\n            while ((int)selected.size() > P && ptr < (int)removable.size()) {\n                int rm = removable[ptr++];\n                auto it = find(selected.begin(), selected.end(), rm);\n                if (it != selected.end()) selected.erase(it);\n            }\n            while ((int)selected.size() > P) selected.pop_back();\n        }\n\n        vector<int> globOfLocal(P);\n        for (int i = 0; i < P; i++) globOfLocal[i] = selected[i];\n\n        // local importance (used by unary term + initialization)\n        vector<int> impLocal(P);\n        for (int i = 0; i < P; i++) {\n            int g = globOfLocal[i];\n            impLocal[i] = seeds[g].V * 10 + seeds[g].peak * 3;\n        }\n\n        vector<int> localSorted(P);\n        iota(localSorted.begin(), localSorted.end(), 0);\n        sort(localSorted.begin(), localSorted.end(), [&](int a, int b) {\n            if (impLocal[a] != impLocal[b]) return impLocal[a] > impLocal[b];\n            return a < b;\n        });\n\n        // ---- Pair weights: potential-based (the strong core) ----\n        double lambdaDiff = 1.6 + 2.5 * phase;\n        double rhoMinV    = 0.06 + 0.42 * phase;\n        double muAbs      = 0.001 + 0.004 * phase;\n\n        vector<vector<double>> w(P, vector<double>(P, 0.0));\n        for (int i = 0; i < P; i++) {\n            for (int j = i + 1; j < P; j++) {\n                const Seed& A = seeds[globOfLocal[i]];\n                const Seed& B = seeds[globOfLocal[j]];\n                int pot = potentialSumMax(A, B, M);\n                int d = diffCount(A, B, M);\n                int sad = sumAbsDiff(A, B, M);\n                int mn = min(A.V, B.V);\n                double score = (double)pot + rhoMinV * (double)mn\n                             - lambdaDiff * (double)d - muAbs * (double)sad;\n                w[i][j] = w[j][i] = score;\n            }\n        }\n\n        // Unary (node) term: keep strong seeds on high-degree cells.\n        // Small coefficient to avoid distorting pair selection.\n        double alphaUnary = 0.012 + 0.010 * phase; // 0.012 -> 0.022\n\n        // ---- Initial layouts (same set as the best-performing style) ----\n        // init0: importance -> high degree\n        vector<int> init0(P);\n        for (int k = 0; k < P; k++) init0[posOrder[k]] = localSorted[k];\n\n        // init1: random permutation\n        vector<int> init1 = init0;\n        for (int i = P - 1; i > 0; i--) swap(init1[i], init1[rng.nextInt(i + 1)]);\n\n        // init2: greedy incremental\n        vector<int> init2(P, -1);\n        vector<char> used2(P, 0);\n        for (int idxPos = 0; idxPos < P; idxPos++) {\n            int pos = posOrder[idxPos];\n            int bestL = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!used2[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init2[nb] != -1) gain += w[li][init2[nb]];\n                gain += alphaUnary * (double)degree[pos] * (double)impLocal[li];\n                if (gain > bestGain) { bestGain = gain; bestL = li; }\n            }\n            init2[pos] = bestL;\n            used2[bestL] = 1;\n        }\n\n        // init3: hub around best seed at a center (structured but not too strong)\n        int champ = localSorted[0];\n        int centerPos = centers.empty() ? posOrder[0] : centers[rng.nextInt((int)centers.size())];\n        vector<int> init3(P, -1);\n        vector<char> used3(P, 0);\n        init3[centerPos] = champ;\n        used3[champ] = 1;\n\n        for (int nb : neigh[centerPos]) {\n            int best = -1;\n            double bestS = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double s = w[champ][li] + 0.001 * (double)impLocal[li];\n                if (s > bestS) { bestS = s; best = li; }\n            }\n            if (best != -1) { init3[nb] = best; used3[best] = 1; }\n        }\n        for (int pos = 0; pos < P; pos++) {\n            if (init3[pos] != -1) continue;\n            int best = -1;\n            double bestGain = -1e100;\n            for (int li = 0; li < P; li++) if (!used3[li]) {\n                double gain = 0.0;\n                for (int nb : neigh[pos]) if (init3[nb] != -1) gain += w[li][init3[nb]];\n                gain += alphaUnary * (double)degree[pos] * (double)impLocal[li];\n                if (gain > bestGain) { bestGain = gain; best = li; }\n            }\n            init3[pos] = best;\n            used3[best] = 1;\n        }\n\n        vector<vector<int>> inits = {init0, init2, init3, init1};\n\n        // ---- Run SA on each init within time ----\n        double bestObj = -1e100;\n        vector<int> bestPerm = init0;\n\n        for (int r = 0; r < (int)inits.size(); r++) {\n            TimePoint nowR = Clock::now();\n            if (nowR >= turnEnd) break;\n            int left = (int)inits.size() - r;\n            double remSec = chrono::duration<double>(turnEnd - nowR).count();\n            TimePoint endR = nowR + chrono::duration_cast<Clock::duration>(chrono::duration<double>(remSec / left));\n            auto res = runSA(inits[r], w, impLocal, alphaUnary, endR);\n            if (res.first > bestObj) {\n                bestObj = res.first;\n                bestPerm = std::move(res.second);\n            }\n        }\n\n        // ---- Output ----\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int pos = id(i, j);\n                int localIdx = bestPerm[pos];      // local seed index\n                int globalIdx = globOfLocal[localIdx];\n                if (j) cout << ' ';\n                cout << globalIdx;\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        readSeeds();\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int dx4[4] = {0, 1, 0, -1}; // 0=R,1=D,2=L,3=U\nstatic const int dy4[4] = {1, 0, -1, 0};\n\nstruct Leaf {\n    int dir;   // 0..3\n    bool hold;\n};\n\nstatic inline int ang_dist(int a, int b) {\n    int d = (a - b + 4) % 4;\n    return min(d, 4 - d);\n}\n\nstruct Params {\n    int highNum, highDen; // collect->deliver when holdCnt >= ceil(K*highNum/highDen)\n    int lowNum, lowDen;   // deliver->collect when holdCnt <= floor(K*lowNum/lowDen)\n\n    bool scanUseImmediate; // false: potential(any dir), true: immediate(.,L,R)\n    long long scanMainW, scanSubW, scanDistW;\n\n    long long immCoef, potCoef, progCoef, centCoef;\n\n    int wPickImm_col, wPlaceImm_col, wPickPot_col, wPlacePot_col;\n    int wPickImm_del, wPlaceImm_del, wPickPot_del, wPlacePot_del;\n};\n\nstruct BestConfig {\n    int initRx, initRy;\n    int presetId;\n    long long score;\n};\n\nstruct SimOutput {\n    long long score;\n    int turns;\n    bool complete;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto global_start = chrono::steady_clock::now();\n    auto global_elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n    };\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    const int NN = N * N;\n\n    vector<unsigned char> cur0(NN, 0), target0(NN, 0);\n    for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n        cur0[x * N + y] = (s[x][y] == '1');\n        target0[x * N + y] = (t[x][y] == '1');\n    }\n\n    vector<unsigned char> isSur0(NN, 0), isDef0(NN, 0);\n    long long surCount0 = 0, defCount0 = 0;\n    long long sumSurX0 = 0, sumSurY0 = 0, sumDefX0 = 0, sumDefY0 = 0;\n\n    for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n        int idx = x * N + y;\n        if (cur0[idx] && !target0[idx]) {\n            isSur0[idx] = 1;\n            surCount0++;\n            sumSurX0 += x; sumSurY0 += y;\n        } else if (!cur0[idx] && target0[idx]) {\n            isDef0[idx] = 1;\n            defCount0++;\n            sumDefX0 += x; sumDefY0 += y;\n        }\n    }\n\n    auto inside = [&](int x, int y) -> bool {\n        return (0 <= x && x < N && 0 <= y && y < N);\n    };\n\n    // Arm: star with V'=V, lengths 1..K\n    int Vp = V;\n    int K = Vp - 1;\n    vector<int> lengths(K);\n    for (int i = 0; i < K; i++) lengths[i] = i + 1;\n\n    // Precompute endpoints: endIdx[leaf][rootPos][dir] -> cell index or -1\n    vector<vector<array<int, 4>>> endIdx(K, vector<array<int, 4>>(NN));\n    for (int i = 0; i < K; i++) {\n        int L = lengths[i];\n        for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n            int p = x * N + y;\n            array<int, 4> arr;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx4[d] * L;\n                int ny = y + dy4[d] * L;\n                arr[d] = inside(nx, ny) ? (nx * N + ny) : -1;\n            }\n            endIdx[i][p] = arr;\n        }\n    }\n\n    auto clamp_pos = [&](int x, int y) -> pair<int,int> {\n        x = min(max(x, 0), N - 1);\n        y = min(max(y, 0), N - 1);\n        return {x, y};\n    };\n    auto centroid = [&](long long sx, long long sy, long long cnt) -> pair<int,int> {\n        if (cnt <= 0) return {N / 2, N / 2};\n        return clamp_pos((int)(sx / cnt), (int)(sy / cnt));\n    };\n\n    // Candidate initial roots\n    vector<pair<int,int>> initCandidates;\n    {\n        long long need = surCount0 + defCount0;\n        auto cNeed = centroid(sumSurX0 + sumDefX0, sumSurY0 + sumDefY0, max(1LL, need));\n        auto cSur = (surCount0 > 0) ? centroid(sumSurX0, sumSurY0, surCount0) : cNeed;\n        auto cDef = (defCount0 > 0) ? centroid(sumDefX0, sumDefY0, defCount0) : cNeed;\n        auto cMid = make_pair(N/2, N/2);\n        initCandidates = {cNeed, cSur, cDef, cMid};\n        // small offsets around cNeed\n        for (int d : {2, -2}) {\n            initCandidates.push_back(clamp_pos(cNeed.first + d, cNeed.second));\n            initCandidates.push_back(clamp_pos(cNeed.first, cNeed.second + d));\n        }\n        sort(initCandidates.begin(), initCandidates.end());\n        initCandidates.erase(unique(initCandidates.begin(), initCandidates.end()), initCandidates.end());\n    }\n\n    // Presets\n    vector<Params> presets;\n    {\n        Params A;\n        A.highNum = 2; A.highDen = 3;\n        A.lowNum  = 1; A.lowDen  = 3;\n        A.scanUseImmediate = false;\n        A.scanMainW = 1200; A.scanSubW = 200; A.scanDistW = 25;\n        A.immCoef = 1000000LL; A.potCoef = 2500LL; A.progCoef = 32000LL; A.centCoef = 35LL;\n        A.wPickImm_col=3; A.wPlaceImm_col=1; A.wPickPot_col=3; A.wPlacePot_col=1;\n        A.wPickImm_del=1; A.wPlaceImm_del=3; A.wPickPot_del=1; A.wPlacePot_del=3;\n        presets.push_back(A);\n\n        Params B = A;\n        B.highNum = 1; B.highDen = 2;\n        B.lowNum  = 1; B.lowDen  = 4;\n        B.progCoef = 38000LL;\n        B.potCoef  = 2200LL;\n        presets.push_back(B);\n\n        Params C = A;\n        C.scanUseImmediate = true;\n        C.scanMainW = 1500; C.scanSubW = 100; C.scanDistW = 22;\n        presets.push_back(C);\n    }\n\n    // Moves\n    const char mvChar[5] = {'.','U','D','L','R'};\n    const int mvDx[5] = {0,-1,1,0,0};\n    const int mvDy[5] = {0,0,0,-1,1};\n\n    auto simulate = [&](const Params& P, int initRx, int initRy, bool record, vector<string>* outOps) -> SimOutput {\n        vector<unsigned char> isSur = isSur0, isDef = isDef0;\n        long long surCount = surCount0, defCount = defCount0;\n        long long sumSurX = sumSurX0, sumSurY = sumSurY0, sumDefX = sumDefX0, sumDefY = sumDefY0;\n\n        vector<Leaf> leaves(K);\n        for (int i = 0; i < K; i++) leaves[i] = Leaf{0, false};\n\n        auto can_pick_idx  = [&](int idx) -> bool { return idx >= 0 && isSur[idx]; };\n        auto can_place_idx = [&](int idx) -> bool { return idx >= 0 && isDef[idx]; };\n\n        auto has_any_target_dir = [&](int leafId, int rootPos) -> bool {\n            const Leaf &lf = leaves[leafId];\n            const auto &arr = endIdx[leafId][rootPos];\n            if (!lf.hold) {\n                return (arr[0] >= 0 && isSur[arr[0]]) || (arr[1] >= 0 && isSur[arr[1]]) ||\n                       (arr[2] >= 0 && isSur[arr[2]]) || (arr[3] >= 0 && isSur[arr[3]]);\n            } else {\n                return (arr[0] >= 0 && isDef[arr[0]]) || (arr[1] >= 0 && isDef[arr[1]]) ||\n                       (arr[2] >= 0 && isDef[arr[2]]) || (arr[3] >= 0 && isDef[arr[3]]);\n            }\n        };\n\n        auto can_act_immediately = [&](int leafId, int rootPos) -> bool {\n            const Leaf &lf = leaves[leafId];\n            int d0 = lf.dir;\n            int dL = (d0 + 3) & 3;\n            int dR = (d0 + 1) & 3;\n            const auto &arr = endIdx[leafId][rootPos];\n            if (!lf.hold) {\n                return can_pick_idx(arr[d0]) || can_pick_idx(arr[dL]) || can_pick_idx(arr[dR]);\n            } else {\n                return can_place_idx(arr[d0]) || can_place_idx(arr[dL]) || can_place_idx(arr[dR]);\n            }\n        };\n\n        auto decide_rot_and_action = [&](int leafId, int rootPos) -> pair<char,bool> {\n            const Leaf &lf = leaves[leafId];\n            int d0 = lf.dir;\n            int dL = (d0 + 3) & 3;\n            int dR = (d0 + 1) & 3;\n            const auto &arr = endIdx[leafId][rootPos];\n\n            if (!lf.hold) {\n                if (can_pick_idx(arr[d0])) return {'.', true};\n                if (can_pick_idx(arr[dL])) return {'L', true};\n                if (can_pick_idx(arr[dR])) return {'R', true};\n            } else {\n                if (can_place_idx(arr[d0])) return {'.', true};\n                if (can_place_idx(arr[dL])) return {'L', true};\n                if (can_place_idx(arr[dR])) return {'R', true};\n            }\n\n            int useful[4], ucnt = 0;\n            if (!lf.hold) {\n                for (int d = 0; d < 4; d++) if (can_pick_idx(arr[d])) useful[ucnt++] = d;\n            } else {\n                for (int d = 0; d < 4; d++) if (can_place_idx(arr[d])) useful[ucnt++] = d;\n            }\n            if (ucnt == 0) return {'.', false};\n\n            auto mindist = [&](int nd) -> int {\n                int best = 10;\n                for (int i = 0; i < ucnt; i++) best = min(best, ang_dist(nd, useful[i]));\n                return best;\n            };\n\n            int dist0 = mindist(d0);\n            int distL = mindist(dL);\n            int distR = mindist(dR);\n\n            if (dist0 <= distL && dist0 <= distR) return {'.', false};\n            if (distL <= distR) return {'L', false};\n            return {'R', false};\n        };\n\n        int rx = initRx, ry = initRy;\n        int targetRx = rx, targetRy = ry;\n        bool haveTarget = false;\n\n        int noActStreak = 0;\n        int phase = 0;\n        int holdCnt = 0;\n\n        int highTh = (int)((1LL * K * P.highNum + P.highDen - 1) / P.highDen);\n        int lowTh  = (int)((1LL * K * P.lowNum) / P.lowDen);\n\n        int scanInterval = (N <= 20 ? 30 : 45);\n\n        auto recompute_best_root_target = [&]() {\n            long long bestScore = LLONG_MIN;\n            int bestX = rx, bestY = ry;\n\n            for (int x = 0; x < N; x++) for (int y = 0; y < N; y++) {\n                int p = x * N + y;\n                int aPick = 0, aPlace = 0;\n                for (int i = 0; i < K; i++) {\n                    bool ok = P.scanUseImmediate ? can_act_immediately(i, p) : has_any_target_dir(i, p);\n                    if (!ok) continue;\n                    if (!leaves[i].hold) aPick++;\n                    else aPlace++;\n                }\n                int dist = abs(rx - x) + abs(ry - y);\n                long long score;\n                if (phase == 0) score = P.scanMainW * aPick + P.scanSubW * aPlace - P.scanDistW * dist;\n                else            score = P.scanSubW * aPick + P.scanMainW * aPlace - P.scanDistW * dist;\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestX = x; bestY = y;\n                }\n            }\n            targetRx = bestX;\n            targetRy = bestY;\n            haveTarget = true;\n        };\n\n        if (record) {\n            outOps->clear();\n            outOps->reserve(20000);\n        }\n\n        int turn = 0;\n        for (; turn < 100000; turn++) {\n            if (surCount == 0 && defCount == 0) break;\n\n            if (phase == 0) {\n                if (holdCnt >= highTh || surCount == 0) phase = 1;\n            } else {\n                if (holdCnt <= lowTh && surCount > 0) phase = 0;\n            }\n\n            if (haveTarget && rx == targetRx && ry == targetRy && noActStreak > 6) haveTarget = false;\n\n            if (!haveTarget || (turn % scanInterval == 0) || noActStreak > 25) {\n                recompute_best_root_target();\n            }\n\n            long long needCnt = surCount + defCount;\n            long long sumNeedX = sumSurX + sumDefX;\n            long long sumNeedY = sumSurY + sumDefY;\n\n            int wPickImm, wPlaceImm, wPickPot, wPlacePot;\n            if (phase == 0) {\n                wPickImm = P.wPickImm_col; wPlaceImm = P.wPlaceImm_col;\n                wPickPot = P.wPickPot_col; wPlacePot = P.wPlacePot_col;\n            } else {\n                wPickImm = P.wPickImm_del; wPlaceImm = P.wPlaceImm_del;\n                wPickPot = P.wPickPot_del; wPlacePot = P.wPlacePot_del;\n            }\n\n            auto eval_move = [&](int mv) -> long long {\n                int nrx = rx + mvDx[mv], nry = ry + mvDy[mv];\n                if (!(0 <= nrx && nrx < N && 0 <= nry && nry < N)) return LLONG_MIN / 4;\n                int np = nrx * N + nry;\n\n                int immPick = 0, immPlace = 0;\n                int potPick = 0, potPlace = 0;\n                for (int i = 0; i < K; i++) {\n                    bool imm = can_act_immediately(i, np);\n                    bool pot = has_any_target_dir(i, np);\n                    if (!leaves[i].hold) { immPick += imm; potPick += pot; }\n                    else { immPlace += imm; potPlace += pot; }\n                }\n\n                int before = abs(rx - targetRx) + abs(ry - targetRy);\n                int after  = abs(nrx - targetRx) + abs(nry - targetRy);\n                int progress = before - after;\n\n                long long centroidDist = 0;\n                if (needCnt > 0) {\n                    centroidDist =\n                        (llabs(1LL * nrx * needCnt - sumNeedX) + llabs(1LL * nry * needCnt - sumNeedY)) / needCnt;\n                }\n\n                long long immScore = 1LL * wPickImm * immPick + 1LL * wPlaceImm * immPlace;\n                long long potScore = 1LL * wPickPot * potPick + 1LL * wPlacePot * potPlace;\n\n                return P.immCoef * immScore + P.potCoef * potScore + P.progCoef * progress - P.centCoef * centroidDist;\n            };\n\n            int bestMove = 0;\n            long long bestVal = LLONG_MIN;\n            for (int mv = 0; mv < 5; mv++) {\n                long long v = eval_move(mv);\n                if (v > bestVal) { bestVal = v; bestMove = mv; }\n            }\n\n            int nrx = rx + mvDx[bestMove], nry = ry + mvDy[bestMove];\n            if (!inside(nrx, nry)) { bestMove = 0; nrx = rx; nry = ry; }\n            int np = nrx * N + nry;\n\n            array<char, 15> rotCmd{};\n            array<char, 15> actOut{};\n            rotCmd.fill('.');\n            actOut.fill('.');\n\n            // Decide rotations and \"intent to act\"\n            for (int i = 0; i < K; i++) {\n                auto [rc, doP] = decide_rot_and_action(i, np);\n                rotCmd[i] = rc;\n                actOut[i] = doP ? 'P' : '.';\n            }\n\n            // Apply move\n            rx = nrx; ry = nry;\n\n            // Apply rotations\n            for (int i = 0; i < K; i++) {\n                if (rotCmd[i] == 'L') leaves[i].dir = (leaves[i].dir + 3) & 3;\n                else if (rotCmd[i] == 'R') leaves[i].dir = (leaves[i].dir + 1) & 3;\n            }\n\n            // Apply actions; if fails, output '.' instead of 'P'\n            int executed = 0;\n            int rp = rx * N + ry;\n            for (int i = 0; i < K; i++) {\n                if (actOut[i] != 'P') continue;\n                int idx = endIdx[i][rp][leaves[i].dir];\n                bool ok = false;\n                if (!leaves[i].hold) {\n                    if (idx >= 0 && isSur[idx]) {\n                        ok = true;\n                        leaves[i].hold = true;\n                        holdCnt++;\n                        isSur[idx] = 0;\n                        surCount--;\n                        int x = idx / N, y = idx % N;\n                        sumSurX -= x; sumSurY -= y;\n                    }\n                } else {\n                    if (idx >= 0 && isDef[idx]) {\n                        ok = true;\n                        leaves[i].hold = false;\n                        holdCnt--;\n                        isDef[idx] = 0;\n                        defCount--;\n                        int x = idx / N, y = idx % N;\n                        sumDefX -= x; sumDefY -= y;\n                    }\n                }\n                if (ok) executed++;\n                else actOut[i] = '.';\n            }\n\n            if (record) {\n                string cmd(2 * Vp, '.');\n                cmd[0] = mvChar[bestMove];\n                for (int i = 0; i < K; i++) cmd[1 + i] = rotCmd[i];\n                cmd[Vp + 0] = '.';\n                for (int i = 0; i < K; i++) cmd[Vp + 1 + i] = actOut[i];\n                outOps->push_back(std::move(cmd));\n            }\n\n            noActStreak = (executed > 0) ? 0 : (noActStreak + 1);\n        }\n\n        long long missing = max(surCount, defCount);\n        long long absScore = (missing == 0) ? (long long)turn : (100000LL + 1000LL * missing);\n        return SimOutput{absScore, turn, missing == 0};\n    };\n\n    // Search best configuration under a global time budget\n    const double SEARCH_LIMIT = 1.65; // leave time for final recording run\n    BestConfig best{initCandidates[0].first, initCandidates[0].second, 0, (1LL<<62)};\n\n    for (int pid = 0; pid < (int)presets.size(); pid++) {\n        for (auto [ix, iy] : initCandidates) {\n            if (global_elapsed() > SEARCH_LIMIT) break;\n            SimOutput res = simulate(presets[pid], ix, iy, false, nullptr);\n            if (res.score < best.score) {\n                best = BestConfig{ix, iy, pid, res.score};\n            }\n        }\n        if (global_elapsed() > SEARCH_LIMIT) break;\n    }\n\n    // Final run (full heuristic, independent of global time)\n    vector<string> ops;\n    ops.reserve(100000);\n    simulate(presets[best.presetId], best.initRx, best.initRy, true, &ops);\n\n    // Output arm design\n    cout << Vp << \"\\n\";\n    for (int u = 1; u < Vp; u++) {\n        cout << 0 << \" \" << lengths[u - 1] << \"\\n\";\n    }\n    cout << best.initRx << \" \" << best.initRy << \"\\n\";\n    for (auto &c : ops) cout << c << \"\\n\";\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n};\n\nstruct XorShift {\n    uint64_t x = 88172645463325252ull;\n    explicit XorShift(uint64_t seed = 0) { if (seed) x ^= seed + 0x9e3779b97f4a7c15ULL; }\n    uint64_t nextU64() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int l, int r) { return l + (int)(nextU64() % (uint64_t)(r - l + 1)); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstatic constexpr int MAXC = 100000;\nstatic constexpr int G = 200;\nstatic constexpr int CELL = 500;\nstatic constexpr int PERIM_LIMIT_EDGES = 800;\n\nstruct Pt { int x, y, w; };\nstruct Rect { int x1, x2, y1, y2; };\n\nstatic inline long long rectPerimeter(const Rect& r) {\n    return 2LL * ((long long)r.x2 - r.x1 + (long long)r.y2 - r.y1);\n}\n\nusing Occ = vector<uint8_t>; // size G*G\nstatic inline int oid(int x, int y) { return y*G + x; }\nstatic inline bool occAt(const Occ& occ, int x, int y) { return occ[oid(x,y)] != 0; }\n\n// ---------------------- 2D BIT (Fenwick of vectors), static points ----------------------\nstruct BIT2D {\n    int nx = 0;\n    vector<int> xs;\n    vector<vector<int>> ys;\n    vector<vector<int>> bit;\n\n    static void add1D(vector<int>& b, int idx, int val) {\n        for (int i = idx; i < (int)b.size(); i += i & -i) b[i] += val;\n    }\n    static int sum1D(const vector<int>& b, int idx) {\n        int s = 0;\n        for (int i = idx; i > 0; i -= i & -i) s += b[i];\n        return s;\n    }\n\n    void build(const vector<Pt>& pts) {\n        xs.clear();\n        xs.reserve(pts.size());\n        for (auto &p : pts) xs.push_back(p.x);\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        nx = (int)xs.size();\n\n        ys.assign(nx + 1, {});\n        for (auto &p : pts) {\n            int xi = (int)(lower_bound(xs.begin(), xs.end(), p.x) - xs.begin()) + 1;\n            for (int x = xi; x <= nx; x += x & -x) ys[x].push_back(p.y);\n        }\n        bit.assign(nx + 1, {});\n        for (int x = 1; x <= nx; x++) {\n            auto &v = ys[x];\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n            bit[x].assign((int)v.size() + 1, 0);\n        }\n        for (auto &p : pts) addPoint(p.x, p.y, p.w);\n    }\n\n    void addPoint(int xval, int yval, int w) {\n        int xi = (int)(lower_bound(xs.begin(), xs.end(), xval) - xs.begin()) + 1;\n        for (int x = xi; x <= nx; x += x & -x) {\n            int yi = (int)(lower_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin()) + 1;\n            add1D(bit[x], yi, w);\n        }\n    }\n\n    int prefix(int xval, int yval) const {\n        int xi = (int)(upper_bound(xs.begin(), xs.end(), xval) - xs.begin());\n        int res = 0;\n        for (int x = xi; x > 0; x -= x & -x) {\n            int yi = (int)(upper_bound(ys[x].begin(), ys[x].end(), yval) - ys[x].begin());\n            res += sum1D(bit[x], yi);\n        }\n        return res;\n    }\n\n    int rectSum(int x1, int x2, int y1, int y2) const {\n        if (x2 < x1 || y2 < y1) return 0;\n        int A = prefix(x2, y2);\n        int B = prefix(x1 - 1, y2);\n        int C = prefix(x2, y1 - 1);\n        int D = prefix(x1 - 1, y1 - 1);\n        return A - B - C + D;\n    }\n};\n\n// ---------------------- polygon evaluation ----------------------\nstatic inline bool onSegAxisAligned(int x, int y, int x1, int y1, int x2, int y2) {\n    if (x1 == x2) {\n        if (x != x1) return false;\n        if (y1 > y2) swap(y1, y2);\n        return y1 <= y && y <= y2;\n    } else if (y1 == y2) {\n        if (y != y1) return false;\n        if (x1 > x2) swap(x1, x2);\n        return x1 <= x && x <= x2;\n    }\n    return false;\n}\n\nstatic bool insidePolyInclusive(const vector<pair<int,int>>& poly, int x, int y) {\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (onSegAxisAligned(x, y, x1, y1, x2, y2)) return true;\n    }\n    bool in = false;\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n        if (x1 == x2) {\n            int xv = x1;\n            int yl = min(y1, y2), yh = max(y1, y2);\n            if (yl < y && y <= yh) if (xv > x) in = !in;\n        }\n    }\n    return in;\n}\n\nstatic int evalPolygonDiff(const vector<Pt>& pts, const vector<pair<int,int>>& poly) {\n    int s = 0;\n    for (auto &p : pts) if (insidePolyInclusive(poly, p.x, p.y)) s += p.w;\n    return s;\n}\n\nstatic long long polygonPerimeter(const vector<pair<int,int>>& poly) {\n    long long per = 0;\n    int m = (int)poly.size();\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        per += llabs(x1-x2) + llabs(y1-y2);\n    }\n    return per;\n}\n\nstatic bool validOutputBasic(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n    if (m < 4 || m > 1000) return false;\n    {\n        vector<pair<int,int>> tmp = poly;\n        sort(tmp.begin(), tmp.end());\n        if (unique(tmp.begin(), tmp.end()) != tmp.end()) return false;\n    }\n    for (auto [x,y] : poly) if (x < 0 || x > MAXC || y < 0 || y > MAXC) return false;\n    for (int i = 0; i < m; i++) {\n        auto [x1,y1] = poly[i];\n        auto [x2,y2] = poly[(i+1)%m];\n        if (!(x1==x2 || y1==y2)) return false;\n        if (x1==x2 && y1==y2) return false;\n    }\n    if (polygonPerimeter(poly) > 400000) return false;\n    return true;\n}\n\n// ---------------------- polyomino (grid) ----------------------\nstruct GridCfg { int ox, oy, xmax, ymax; };\nstatic inline bool inAllowed(const GridCfg& cfg, int x, int y) {\n    return 0 <= x && x <= cfg.xmax && 0 <= y && y <= cfg.ymax;\n}\n\nstatic int computeBoundaryEdges(const Occ& occ) {\n    auto inside = [&](int x, int y)->bool{ return 0 <= x && x < G && 0 <= y && y < G; };\n    int edges = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occAt(occ,x,y)) {\n        if (!inside(x-1,y) || !occAt(occ,x-1,y)) edges++;\n        if (!inside(x+1,y) || !occAt(occ,x+1,y)) edges++;\n        if (!inside(x,y-1) || !occAt(occ,x,y-1)) edges++;\n        if (!inside(x,y+1) || !occAt(occ,x,y+1)) edges++;\n    }\n    return edges;\n}\n\nstatic int computeTotalW(const Occ& occ, const vector<vector<int>>& wgrid) {\n    int s = 0;\n    for (int y = 0; y < G; y++) for (int x = 0; x < G; x++) if (occAt(occ,x,y)) s += wgrid[y][x];\n    return s;\n}\n\nstatic void fillHoles(const GridCfg& cfg, Occ& occ) {\n    Occ vis(G*G, 0);\n    deque<pair<int,int>> dq;\n    auto pushIf = [&](int x, int y) {\n        if (!inAllowed(cfg,x,y)) return;\n        int id = oid(x,y);\n        if (vis[id]) return;\n        if (occ[id]) return;\n        vis[id] = 1;\n        dq.push_back({x,y});\n    };\n    for (int x = 0; x <= cfg.xmax; x++) { pushIf(x,0); pushIf(x,cfg.ymax); }\n    for (int y = 0; y <= cfg.ymax; y++) { pushIf(0,y); pushIf(cfg.xmax,y); }\n\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n    while (!dq.empty()) {\n        auto [x,y] = dq.front(); dq.pop_front();\n        for (int k = 0; k < 4; k++) pushIf(x+dx4[k], y+dy4[k]);\n    }\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n        int id = oid(x,y);\n        if (!occ[id] && !vis[id]) occ[id] = 1;\n    }\n}\n\nstatic void pruneNegativeLeaves(const GridCfg& cfg, Occ& occ, const vector<vector<int>>& wgrid) {\n    vector<int> deg(G*G, 0);\n    int cells = 0;\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (occAt(occ,x,y)) {\n        cells++;\n        int d = 0;\n        if (ok(x-1,y) && occAt(occ,x-1,y)) d++;\n        if (ok(x+1,y) && occAt(occ,x+1,y)) d++;\n        if (ok(x,y-1) && occAt(occ,x,y-1)) d++;\n        if (ok(x,y+1) && occAt(occ,x,y+1)) d++;\n        deg[oid(x,y)] = d;\n    }\n\n    deque<pair<int,int>> q;\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n        if (occAt(occ,x,y) && wgrid[y][x] < 0 && deg[oid(x,y)] <= 1) q.push_back({x,y});\n    }\n\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n    while (!q.empty()) {\n        auto [x,y] = q.front(); q.pop_front();\n        int id = oid(x,y);\n        if (!occ[id]) continue;\n        if (wgrid[y][x] >= 0) continue;\n        if (deg[id] > 1) continue;\n        if (cells <= 1) break;\n\n        occ[id] = 0;\n        cells--;\n\n        for (int k = 0; k < 4; k++) {\n            int nx=x+dx4[k], ny=y+dy4[k];\n            if (!ok(nx,ny) || !occAt(occ,nx,ny)) continue;\n            int nid = oid(nx,ny);\n            deg[nid]--;\n            if (wgrid[ny][nx] < 0 && deg[nid] <= 1) q.push_back({nx,ny});\n        }\n    }\n}\n\nstruct Polyomino { Occ occ; int totalW=0; int boundaryEdges=0; };\n\nstatic Polyomino greedyExpandPolyomino(const GridCfg& cfg, const vector<vector<int>>& wgrid, Occ occInit) {\n    Polyomino P;\n    P.occ = std::move(occInit);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n\n    Occ isCand(G*G, 0);\n    struct Node { int key; int x,y; };\n    struct Cmp { bool operator()(const Node& a, const Node& b) const { return a.key < b.key; } };\n    priority_queue<Node, vector<Node>, Cmp> pq;\n\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n    auto sharedCount = [&](int x, int y)->int{\n        int s = 0;\n        if (ok(x-1,y) && occAt(P.occ,x-1,y)) s++;\n        if (ok(x+1,y) && occAt(P.occ,x+1,y)) s++;\n        if (ok(x,y-1) && occAt(P.occ,x,y-1)) s++;\n        if (ok(x,y+1) && occAt(P.occ,x,y+1)) s++;\n        return s;\n    };\n    auto deltaEdgesAdd = [&](int x, int y)->int{ return 4 - 2*sharedCount(x,y); };\n    auto keyOf = [&](int x, int y)->int{\n        int dw = wgrid[y][x];\n        int de = deltaEdgesAdd(x,y);\n        return dw * 1000 - de * 35;\n    };\n    auto pushCandidate = [&](int x, int y){\n        if (!ok(x,y)) return;\n        int id = oid(x,y);\n        if (P.occ[id] || isCand[id]) return;\n        isCand[id] = 1;\n        pq.push(Node{keyOf(x,y), x, y});\n    };\n\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (occAt(P.occ,x,y)) {\n        pushCandidate(x-1,y); pushCandidate(x+1,y); pushCandidate(x,y-1); pushCandidate(x,y+1);\n    }\n\n    while (!pq.empty()) {\n        auto nd = pq.top(); pq.pop();\n        int x = nd.x, y = nd.y;\n        int id = oid(x,y);\n        if (!isCand[id]) continue;\n        if (P.occ[id]) { isCand[id] = 0; continue; }\n\n        int kNow = keyOf(x,y);\n        if (kNow != nd.key) { pq.push(Node{kNow,x,y}); continue; }\n\n        int dw = wgrid[y][x];\n        int de = deltaEdgesAdd(x,y);\n        if (P.boundaryEdges + de > PERIM_LIMIT_EDGES) { isCand[id] = 0; continue; }\n\n        bool accept = false;\n        if (dw > 0) accept = true;\n        else if (dw == 0 && de < 0) accept = true;\n        else if (dw >= -2 && de <= -2) accept = true;\n        if (!accept) { isCand[id] = 0; continue; }\n\n        P.occ[id] = 1;\n        isCand[id] = 0;\n        P.totalW += dw;\n        P.boundaryEdges += de;\n\n        pushCandidate(x-1,y); pushCandidate(x+1,y); pushCandidate(x,y-1); pushCandidate(x,y+1);\n        if (P.boundaryEdges >= PERIM_LIMIT_EDGES) break;\n    }\n\n    fillHoles(cfg, P.occ);\n    pruneNegativeLeaves(cfg, P.occ, wgrid);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n    return P;\n}\n\n// Best-of-k add/remove; removal only boundary cells\nstatic void localImprovePolyomino(Polyomino& P, const GridCfg& cfg, const vector<vector<int>>& wgrid,\n                                 XorShift& rng, double timeEnd,\n                                 function<double()> elapsedSec) {\n    vector<int> occVec;\n    vector<int> pos(G*G, -1);\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (occAt(P.occ,x,y)) {\n        int id = oid(x,y);\n        pos[id] = (int)occVec.size();\n        occVec.push_back(id);\n    }\n    if (occVec.empty()) return;\n\n    auto ok = [&](int x,int y){ return inAllowed(cfg,x,y); };\n    static const int dx4[4] = {1,-1,0,0};\n    static const int dy4[4] = {0,0,1,-1};\n\n    vector<int> vis(G*G, 0);\n    int stamp = 1;\n\n    auto countNeighbors = [&](int x, int y)->int{\n        int s=0;\n        if (ok(x-1,y) && occAt(P.occ,x-1,y)) s++;\n        if (ok(x+1,y) && occAt(P.occ,x+1,y)) s++;\n        if (ok(x,y-1) && occAt(P.occ,x,y-1)) s++;\n        if (ok(x,y+1) && occAt(P.occ,x,y+1)) s++;\n        return s;\n    };\n\n    auto isBoundaryCell = [&](int x, int y)->bool{\n        if (!ok(x-1,y) || !occAt(P.occ,x-1,y)) return true;\n        if (!ok(x+1,y) || !occAt(P.occ,x+1,y)) return true;\n        if (!ok(x,y-1) || !occAt(P.occ,x,y-1)) return true;\n        if (!ok(x,y+1) || !occAt(P.occ,x,y+1)) return true;\n        return false;\n    };\n\n    auto connectedAfterRemoval = [&](int rx, int ry)->bool{\n        int cells = (int)occVec.size();\n        if (cells <= 1) return false;\n        int rid = oid(rx,ry);\n        int startId = -1;\n        for (int id : occVec) if (id != rid) { startId = id; break; }\n        if (startId < 0) return true;\n\n        stamp++;\n        deque<int> dq;\n        dq.push_back(startId);\n        vis[startId] = stamp;\n        int cnt = 0;\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            cnt++;\n            int x = v % G, y = v / G;\n            for (int k = 0; k < 4; k++) {\n                int nx = x + dx4[k], ny = y + dy4[k];\n                if (!ok(nx,ny)) continue;\n                int nid = oid(nx,ny);\n                if (vis[nid] == stamp) continue;\n                if (!P.occ[nid]) continue;\n                vis[nid] = stamp;\n                dq.push_back(nid);\n            }\n        }\n        return cnt == cells - 1;\n    };\n\n    auto addAccept = [&](int dw, int de)->bool{\n        if (dw > 0) return true;\n        if (dw == 0 && de <= 0) return true;\n        if (dw >= -1 && de <= -2) return true;\n        if (dw >= -3 && de <= -4) return true;\n        return false;\n    };\n\n    const int KADD = 7, KREM = 10;\n\n    while (elapsedSec() < timeEnd) {\n        bool doAdd = (rng.nextInt(0, 99) < 62);\n\n        if (doAdd) {\n            int bestKey = INT_MIN;\n            int bx=-1, by=-1, bde=0, bdw=0;\n\n            for (int t = 0; t < KADD; t++) {\n                int base = occVec[rng.nextInt(0, (int)occVec.size()-1)];\n                int x = base % G, y = base / G;\n                for (int k = 0; k < 4; k++) {\n                    int nx = x + dx4[k], ny = y + dy4[k];\n                    if (!ok(nx,ny)) continue;\n                    int nid = oid(nx,ny);\n                    if (P.occ[nid]) continue;\n\n                    int sh = countNeighbors(nx, ny);\n                    int de = 4 - 2*sh;\n                    if (P.boundaryEdges + de > PERIM_LIMIT_EDGES) continue;\n                    int dw = wgrid[ny][nx];\n                    if (!addAccept(dw, de)) continue;\n\n                    int key = dw * 1000 - de * 45 + sh * 8;\n                    if (key > bestKey) {\n                        bestKey = key;\n                        bx = nx; by = ny; bde = de; bdw = dw;\n                    }\n                }\n            }\n            if (bx == -1) continue;\n\n            int id = oid(bx,by);\n            P.occ[id] = 1;\n            pos[id] = (int)occVec.size();\n            occVec.push_back(id);\n            P.totalW += bdw;\n            P.boundaryEdges += bde;\n        } else {\n            if ((int)occVec.size() <= 1) continue;\n\n            int bestGain = INT_MIN;\n            int rx=-1, ry=-1, rde=0, rdw=0, rid=-1;\n\n            for (int t = 0; t < KREM; t++) {\n                int id = occVec[rng.nextInt(0, (int)occVec.size()-1)];\n                int x = id % G, y = id / G;\n                int dw = wgrid[y][x];\n                if (dw > 0) continue;\n                if (!isBoundaryCell(x,y)) continue;\n\n                int sh = countNeighbors(x, y);\n                if (sh == 0) continue;\n                int deRemove = -(4 - 2*sh);\n                if (P.boundaryEdges + deRemove > PERIM_LIMIT_EDGES) continue;\n                if (dw == 0 && deRemove >= 0) continue;\n\n                int gain = (-dw) * 1000 + (-deRemove) * 30 - sh * 2;\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    rx = x; ry = y; rde = deRemove; rdw = dw; rid = id;\n                }\n            }\n            if (rx == -1) continue;\n\n            P.occ[rid] = 0;\n            bool okc = connectedAfterRemoval(rx, ry);\n            if (!okc) {\n                P.occ[rid] = 1;\n                continue;\n            }\n\n            int idx = pos[rid];\n            int last = occVec.back();\n            occVec[idx] = last;\n            pos[last] = idx;\n            occVec.pop_back();\n            pos[rid] = -1;\n\n            P.totalW -= rdw;\n            P.boundaryEdges += rde;\n        }\n    }\n\n    fillHoles(cfg, P.occ);\n    pruneNegativeLeaves(cfg, P.occ, wgrid);\n    P.boundaryEdges = computeBoundaryEdges(P.occ);\n    P.totalW = computeTotalW(P.occ, wgrid);\n}\n\n// compress collinear cyclic\nstatic bool collinearAxis(const pair<int,int>& a, const pair<int,int>& b, const pair<int,int>& c) {\n    return (a.first == b.first && b.first == c.first) || (a.second == b.second && b.second == c.second);\n}\nstatic vector<pair<int,int>> compressCollinearCyclic(vector<pair<int,int>> v) {\n    vector<pair<int,int>> w;\n    for (auto &p : v) if (w.empty() || w.back() != p) w.push_back(p);\n    v.swap(w);\n    if (v.size() >= 2 && v.front() == v.back()) v.pop_back();\n\n    bool changed = true;\n    while (changed && v.size() >= 4) {\n        changed = false;\n        int n = (int)v.size();\n        vector<char> del(n, 0);\n        for (int i = 0; i < n; i++) {\n            int ip = (i - 1 + n) % n;\n            int in = (i + 1) % n;\n            if (collinearAxis(v[ip], v[i], v[in])) del[i] = 1;\n        }\n        int cnt = 0;\n        for (int i = 0; i < n; i++) if (!del[i]) cnt++;\n        if (cnt < n && cnt >= 4) {\n            vector<pair<int,int>> nv;\n            nv.reserve(cnt);\n            for (int i = 0; i < n; i++) if (!del[i]) nv.push_back(v[i]);\n            v.swap(nv);\n            changed = true;\n        }\n    }\n    return v;\n}\n\n// boundary extraction from occ using directed CCW edges\nstatic bool extractBoundaryPolygon(const GridCfg& cfg, const Occ& occ, vector<pair<int,int>>& outPoly) {\n    const int W = G + 1;\n    const int V = W * W;\n    auto vid = [&](int x, int y)->int{ return y * W + x; };\n    auto vxy = [&](int id)->pair<int,int>{ return {id % W, id / W}; };\n\n    vector<int> nxt(V, -1);\n    vector<char> hasOut(V, 0);\n    bool conflict = false;\n\n    auto cellOcc = [&](int x, int y)->bool{\n        if (!inAllowed(cfg,x,y)) return false;\n        return occAt(occ,x,y);\n    };\n    auto addEdge = [&](int x1,int y1,int x2,int y2){\n        int a = vid(x1,y1), b = vid(x2,y2);\n        if (nxt[a] == -1) { nxt[a] = b; hasOut[a] = 1; }\n        else if (nxt[a] != b) conflict = true;\n    };\n\n    for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) if (cellOcc(x,y)) {\n        if (!cellOcc(x, y-1)) addEdge(x, y, x+1, y);\n        if (!cellOcc(x+1, y)) addEdge(x+1, y, x+1, y+1);\n        if (!cellOcc(x, y+1)) addEdge(x+1, y+1, x, y+1);\n        if (!cellOcc(x-1, y)) addEdge(x, y+1, x, y);\n    }\n    if (conflict) return false;\n\n    int start = -1;\n    for (int id = 0; id < V; id++) if (hasOut[id]) {\n        if (start == -1) start = id;\n        else {\n            auto [x1,y1] = vxy(id);\n            auto [x0,y0] = vxy(start);\n            if (y1 < y0 || (y1 == y0 && x1 < x0)) start = id;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<pair<int,int>> gridPath;\n    gridPath.reserve(6000);\n    int cur = start;\n    for (int steps = 0; steps < 900000; steps++) {\n        gridPath.push_back(vxy(cur));\n        int to = nxt[cur];\n        if (to == -1) break;\n        cur = to;\n        if (cur == start) break;\n    }\n    if (gridPath.size() < 4) return false;\n\n    vector<pair<int,int>> poly;\n    poly.reserve(gridPath.size());\n    for (auto [gx,gy] : gridPath) {\n        long long X = (long long)cfg.ox + (long long)gx * CELL;\n        long long Y = (long long)cfg.oy + (long long)gy * CELL;\n        if (X < 0 || X > MAXC || Y < 0 || Y > MAXC) return false;\n        poly.push_back({(int)X, (int)Y});\n    }\n    poly = compressCollinearCyclic(poly);\n    outPoly.swap(poly);\n    return true;\n}\n\n// ---------------------- grid building and max sub-rectangle ----------------------\nstatic void buildWGrid(const GridCfg& cfg, const vector<Pt>& pts, vector<vector<int>>& wgrid) {\n    for (int y = 0; y < G; y++) fill(wgrid[y].begin(), wgrid[y].end(), 0);\n    for (auto &p : pts) {\n        int rx = p.x - cfg.ox;\n        int ry = p.y - cfg.oy;\n        if (rx < 0 || ry < 0) continue;\n        int gx = rx / CELL;\n        int gy = ry / CELL;\n        if (!inAllowed(cfg, gx, gy)) continue;\n        wgrid[gy][gx] += p.w;\n    }\n}\n\nstatic tuple<int,int,int,int,int> maxSumSubRect(const GridCfg& cfg, const vector<vector<int>>& wgrid) {\n    int W = cfg.xmax + 1;\n    int H = cfg.ymax + 1;\n    int bestSum = INT_MIN;\n    int bestL=0,bestR=0,bestB=0,bestT=0;\n    vector<int> colSum(H);\n    for (int L = 0; L < W; L++) {\n        fill(colSum.begin(), colSum.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) colSum[y] += wgrid[y][R];\n            int cur = 0, curStart = 0;\n            int localBest = INT_MIN, localB = 0, localT = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) { cur = colSum[y]; curStart = y; }\n                else cur += colSum[y];\n                if (cur > localBest) { localBest = cur; localB = curStart; localT = y; }\n            }\n            if (localBest > bestSum) {\n                bestSum = localBest;\n                bestL=L; bestR=R; bestB=localB; bestT=localT;\n            }\n        }\n    }\n    return {bestSum,bestL,bestR,bestB,bestT};\n}\n\nstatic int bestShortestPathWeightDP(const GridCfg& cfg, const vector<vector<int>>& wgrid,\n                                   int x1,int y1,int x2,int y2, bool reconstruct,\n                                   vector<pair<int,int>>* outCells) {\n    if (!inAllowed(cfg,x1,y1) || !inAllowed(cfg,x2,y2)) return INT_MIN/4;\n    int sx = (x2 >= x1 ? 1 : -1);\n    int sy = (y2 >= y1 ? 1 : -1);\n    int ax = abs(x2 - x1);\n    int ay = abs(y2 - y1);\n    int WW = ax + 1;\n    int HH = ay + 1;\n    const int NEG = -1000000000;\n\n    vector<int> dp(WW*HH, NEG);\n    vector<unsigned char> pre;\n    if (reconstruct) pre.assign(WW*HH, 0);\n\n    auto idx = [&](int i,int j){ return j*WW + i; };\n    auto cell = [&](int i,int j)->pair<int,int>{ return {x1 + i*sx, y1 + j*sy}; };\n\n    dp[idx(0,0)] = wgrid[y1][x1];\n    for (int j = 0; j < HH; j++) for (int i = 0; i < WW; i++) {\n        if (i==0 && j==0) continue;\n        int best = NEG;\n        unsigned char p = 0;\n        if (i > 0 && dp[idx(i-1,j)] > best) { best = dp[idx(i-1,j)]; p = 0; }\n        if (j > 0 && dp[idx(i,j-1)] > best) { best = dp[idx(i,j-1)]; p = 1; }\n        auto [cx,cy] = cell(i,j);\n        dp[idx(i,j)] = best + wgrid[cy][cx];\n        if (reconstruct) pre[idx(i,j)] = p;\n    }\n\n    int res = dp[idx(ax,ay)];\n    if (!reconstruct || !outCells) return res;\n\n    outCells->clear();\n    outCells->reserve(ax + ay + 1);\n    int i = ax, j = ay;\n    while (!(i==0 && j==0)) {\n        auto [cx,cy] = cell(i,j);\n        outCells->push_back({cx,cy});\n        unsigned char p = pre[idx(i,j)];\n        if (p == 0) i--;\n        else j--;\n    }\n    outCells->push_back({x1,y1});\n    reverse(outCells->begin(), outCells->end());\n    return res;\n}\n\nstatic bool containsAnyRect(const vector<Pt>& pts, const Rect& r) {\n    for (auto &p : pts) if (r.x1 <= p.x && p.x <= r.x2 && r.y1 <= p.y && p.y <= r.y2) return true;\n    return false;\n}\n\nstruct OccCand { int cfgId; Occ occ; int approx; };\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<Pt> pts;\n    pts.reserve(2*N);\n\n    SplitMix64 sm(123456789);\n    uint64_t hseed = 0;\n    for (int i = 0; i < 2*N; i++) {\n        int x,y; cin >> x >> y;\n        int w = (i < N ? +1 : -1);\n        pts.push_back(Pt{x,y,w});\n        uint64_t v = ((uint64_t)(uint32_t)x << 32) ^ (uint64_t)(uint32_t)y ^ (uint64_t)(w + 7);\n        sm.x ^= v + 0x9e3779b97f4a7c15ULL;\n        hseed ^= sm.next();\n    }\n    XorShift rng(hseed);\n\n    auto startTime = chrono::high_resolution_clock::now();\n    auto elapsedSec = [&]()->double{\n        auto now = chrono::high_resolution_clock::now();\n        return chrono::duration<double>(now - startTime).count();\n    };\n\n    // Rectangle SA baseline\n    BIT2D bit2d;\n    bit2d.build(pts);\n    auto evalRectFast = [&](const Rect& r)->int{\n        return bit2d.rectSum(r.x1, r.x2, r.y1, r.y2);\n    };\n\n    auto clampi = [&](int v){ return max(0, min(MAXC, v)); };\n\n    Rect bestRect{0, MAXC, 0, MAXC};\n    int bestRectDiff = evalRectFast(bestRect);\n\n    auto randomRectAround = [&]()->Rect{\n        const Pt& p = pts[rng.nextInt(0, (int)pts.size()-1)];\n        int wx = rng.nextInt(500, 25000);\n        int wy = rng.nextInt(500, 25000);\n        int x1 = clampi(p.x - wx), x2 = clampi(p.x + wx);\n        int y1 = clampi(p.y - wy), y2 = clampi(p.y + wy);\n        if (x2 <= x1) x2 = min(MAXC, x1+1);\n        if (y2 <= y1) y2 = min(MAXC, y1+1);\n        return Rect{x1,x2,y1,y2};\n    };\n\n    // candidate coordinates for SA\n    vector<int> candX, candY;\n    candX.reserve(30000);\n    candY.reserve(30000);\n    auto addCand = [&](vector<int>& v, int c){ if (0 <= c && c <= MAXC) v.push_back(c); };\n    addCand(candX, 0); addCand(candX, MAXC);\n    addCand(candY, 0); addCand(candY, MAXC);\n    for (int i = 0; i <= G; i++) { addCand(candX, i*CELL); addCand(candY, i*CELL); }\n    for (int i = 0; i < (int)pts.size(); i += 2) {\n        addCand(candX, pts[i].x); addCand(candX, pts[i].x-1); addCand(candX, pts[i].x+1);\n        addCand(candY, pts[i].y); addCand(candY, pts[i].y-1); addCand(candY, pts[i].y+1);\n    }\n    sort(candX.begin(), candX.end());\n    candX.erase(unique(candX.begin(), candX.end()), candX.end());\n    sort(candY.begin(), candY.end());\n    candY.erase(unique(candY.begin(), candY.end()), candY.end());\n\n    const double SA_TIME = 0.62;\n    const double T0 = 26.0, T1 = 0.9;\n    vector<Rect> starts;\n    for (int i = 0; i < 12; i++) starts.push_back(randomRectAround());\n    starts.push_back(bestRect);\n\n    for (auto st : starts) {\n        if (elapsedSec() > SA_TIME) break;\n        if (rectPerimeter(st) > 400000) continue;\n        Rect cur = st;\n        int curDiff = evalRectFast(cur);\n        while (elapsedSec() < SA_TIME) {\n            double t = elapsedSec() / SA_TIME;\n            double T = T0 * pow(T1 / T0, t);\n            Rect nxt = cur;\n            int side = rng.nextInt(0,3);\n            if (side == 0) {\n                int nx1 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx1 >= nxt.x2) continue;\n                nxt.x1 = nx1;\n            } else if (side == 1) {\n                int nx2 = candX[rng.nextInt(0, (int)candX.size()-1)];\n                if (nx2 <= nxt.x1) continue;\n                nxt.x2 = nx2;\n            } else if (side == 2) {\n                int ny1 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny1 >= nxt.y2) continue;\n                nxt.y1 = ny1;\n            } else {\n                int ny2 = candY[rng.nextInt(0, (int)candY.size()-1)];\n                if (ny2 <= nxt.y1) continue;\n                nxt.y2 = ny2;\n            }\n            if (rectPerimeter(nxt) > 400000) continue;\n            int nd = evalRectFast(nxt);\n            int delta = nd - curDiff;\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else if (rng.nextDouble() < exp((double)delta / T)) accept = true;\n            if (accept) {\n                cur = nxt;\n                curDiff = nd;\n                if (curDiff > bestRectDiff) { bestRectDiff = curDiff; bestRect = cur; }\n            }\n        }\n    }\n\n    vector<pair<int,int>> bestPoly = {\n        {bestRect.x1, bestRect.y1},\n        {bestRect.x2, bestRect.y1},\n        {bestRect.x2, bestRect.y2},\n        {bestRect.x1, bestRect.y2}\n    };\n    int bestDiff = bestRectDiff;\n\n    // Grid configs (7 offsets)\n    vector<GridCfg> cfgs;\n    cfgs.push_back(GridCfg{0,   0,   199,199});\n    cfgs.push_back(GridCfg{250, 0,   198,199});\n    cfgs.push_back(GridCfg{0,   250, 199,198});\n    cfgs.push_back(GridCfg{250, 250, 198,198});\n    cfgs.push_back(GridCfg{125, 125, 198,198});\n    cfgs.push_back(GridCfg{125, 0,   198,199});\n    cfgs.push_back(GridCfg{0,   125, 199,198});\n\n    // Precompute wgrids\n    vector<vector<vector<int>>> wgrids(cfgs.size(), vector<vector<int>>(G, vector<int>(G,0)));\n    for (int ci = 0; ci < (int)cfgs.size(); ci++) buildWGrid(cfgs[ci], pts, wgrids[ci]);\n\n    vector<OccCand> cands;\n    cands.reserve(100);\n    auto pushCand = [&](int cfgId, Polyomino&& P){\n        cands.push_back(OccCand{cfgId, std::move(P.occ), P.totalW});\n    };\n\n    const double GLOBAL_END = 1.93;\n    Occ seed(G*G, 0);\n    vector<pair<int,int>> path1, path2;\n    vector<pair<int,int>> polyTmp;\n\n    for (int cfgId = 0; cfgId < (int)cfgs.size(); cfgId++) {\n        if (elapsedSec() > GLOBAL_END) break;\n        const auto& cfg = cfgs[cfgId];\n        auto& wgrid = wgrids[cfgId];\n\n        auto [sumBest, L, R, B, T] = maxSumSubRect(cfg, wgrid);\n\n        // top cells\n        vector<tuple<int,int,int>> cells;\n        for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) cells.emplace_back(wgrid[y][x], x, y);\n        sort(cells.begin(), cells.end(), greater<>());\n        int K = (cfgId < 4 ? 18 : 14);\n        K = min(K, (int)cells.size());\n        vector<pair<int,int>> topCells;\n        for (int i = 0; i < K; i++) {\n            auto [w,x,y] = cells[i];\n            if (w <= 0) break;\n            topCells.push_back({x,y});\n        }\n        int M = (int)topCells.size();\n\n        auto makeCandidate = [&](Occ occSeed, double initBudget){\n            if (elapsedSec() > GLOBAL_END) return;\n            Polyomino P = greedyExpandPolyomino(cfg, wgrid, std::move(occSeed));\n            if (P.boundaryEdges > PERIM_LIMIT_EDGES) return;\n            double tEnd = min(GLOBAL_END, elapsedSec() + initBudget);\n            localImprovePolyomino(P, cfg, wgrid, rng, tEnd, elapsedSec);\n            pushCand(cfgId, std::move(P));\n        };\n\n        // A) max-sum rectangle\n        fill(seed.begin(), seed.end(), 0);\n        for (int y = B; y <= T; y++) for (int x = L; x <= R; x++) seed[oid(x,y)] = 1;\n        makeCandidate(seed, 0.014);\n\n        // B) best single cell\n        {\n            int bx=0, by=0, bestW = INT_MIN;\n            for (int y = 0; y <= cfg.ymax; y++) for (int x = 0; x <= cfg.xmax; x++) {\n                if (wgrid[y][x] > bestW) { bestW = wgrid[y][x]; bx=x; by=y; }\n            }\n            if (bestW > 0 || sumBest > 0) {\n                fill(seed.begin(), seed.end(), 0);\n                seed[oid(bx,by)] = 1;\n                makeCandidate(seed, 0.012);\n            }\n        }\n\n        // C) SA-rectangle projected to this grid as an extra seed (often helps)\n        {\n            int lx = (bestRect.x1 - cfg.ox) / CELL;\n            int rx = (bestRect.x2 - cfg.ox) / CELL;\n            int by = (bestRect.y1 - cfg.oy) / CELL;\n            int ty = (bestRect.y2 - cfg.oy) / CELL;\n            lx = max(0, min(cfg.xmax, lx));\n            rx = max(0, min(cfg.xmax, rx));\n            by = max(0, min(cfg.ymax, by));\n            ty = max(0, min(cfg.ymax, ty));\n            if (lx <= rx && by <= ty) {\n                fill(seed.begin(), seed.end(), 0);\n                for (int y = by; y <= ty; y++) for (int x = lx; x <= rx; x++) seed[oid(x,y)] = 1;\n                makeCandidate(seed, 0.010);\n            }\n        }\n\n        if (M >= 2) {\n            // pair candidates\n            struct PairCand { int score; int i,j; int w; int dist; };\n            vector<PairCand> pairs;\n            pairs.reserve(M*M);\n            for (int i = 0; i < M; i++) for (int j = i+1; j < M; j++) {\n                int x1=topCells[i].first, y1=topCells[i].second;\n                int x2=topCells[j].first, y2=topCells[j].second;\n                int dist = abs(x1-x2) + abs(y1-y2);\n                int w = bestShortestPathWeightDP(cfg, wgrid, x1,y1,x2,y2, false, nullptr);\n                int score = w * 120 - dist * 70;\n                pairs.push_back({score,i,j,w,dist});\n            }\n            sort(pairs.begin(), pairs.end(), [](const PairCand& a, const PairCand& b){ return a.score > b.score; });\n\n            int pairTry = (cfgId < 4 ? 4 : 2);\n            pairTry = min(pairTry, (int)pairs.size());\n            for (int t = 0; t < pairTry && elapsedSec() < GLOBAL_END; t++) {\n                auto pc = pairs[t];\n                if (pc.w < 4) continue;\n                int x1=topCells[pc.i].first, y1=topCells[pc.i].second;\n                int x2=topCells[pc.j].first, y2=topCells[pc.j].second;\n                bestShortestPathWeightDP(cfg, wgrid, x1,y1,x2,y2, true, &path1);\n                fill(seed.begin(), seed.end(), 0);\n                for (auto [cx,cy] : path1) seed[oid(cx,cy)] = 1;\n                makeCandidate(seed, 0.010);\n            }\n\n            // triple candidates (only on main configs, and 1 on extra configs)\n            int rootLim = 2;\n            int otherLim = min(8, M);\n            struct TripleCand { int score; int r,a,b; };\n            vector<TripleCand> triples;\n            for (int r = 0; r < min(rootLim, M); r++) {\n                for (int a = 0; a < otherLim; a++) if (a != r) {\n                    for (int b = a+1; b < otherLim; b++) if (b != r) {\n                        int rx=topCells[r].first, ry=topCells[r].second;\n                        int ax=topCells[a].first, ay=topCells[a].second;\n                        int bx=topCells[b].first, by=topCells[b].second;\n                        int wra = bestShortestPathWeightDP(cfg, wgrid, rx,ry,ax,ay, false, nullptr);\n                        int wrb = bestShortestPathWeightDP(cfg, wgrid, rx,ry,bx,by, false, nullptr);\n                        if (wra < 4 || wrb < 4) continue;\n\n                        bestShortestPathWeightDP(cfg, wgrid, rx,ry,ax,ay, true, &path1);\n                        bestShortestPathWeightDP(cfg, wgrid, rx,ry,bx,by, true, &path2);\n\n                        int unionW = 0;\n                        int len = 0;\n                        fill(seed.begin(), seed.end(), 0);\n                        auto addCell = [&](int x,int y){\n                            int id = oid(x,y);\n                            if (!seed[id]) { seed[id] = 1; unionW += wgrid[y][x]; }\n                            len++;\n                        };\n                        for (auto [cx,cy] : path1) addCell(cx,cy);\n                        for (auto [cx,cy] : path2) addCell(cx,cy);\n\n                        int score = unionW * 110 - len * 55;\n                        triples.push_back({score,r,a,b});\n                    }\n                }\n            }\n            sort(triples.begin(), triples.end(), [](const TripleCand& A, const TripleCand& B){ return A.score > B.score; });\n            int triTry = (cfgId < 4 ? 2 : 1);\n            triTry = min(triTry, (int)triples.size());\n            for (int t = 0; t < triTry && elapsedSec() < GLOBAL_END; t++) {\n                auto tc = triples[t];\n                int rx=topCells[tc.r].first, ry=topCells[tc.r].second;\n                int ax=topCells[tc.a].first, ay=topCells[tc.a].second;\n                int bx=topCells[tc.b].first, by=topCells[tc.b].second;\n                bestShortestPathWeightDP(cfg, wgrid, rx,ry,ax,ay, true, &path1);\n                bestShortestPathWeightDP(cfg, wgrid, rx,ry,bx,by, true, &path2);\n                fill(seed.begin(), seed.end(), 0);\n                for (auto [cx,cy] : path1) seed[oid(cx,cy)] = 1;\n                for (auto [cx,cy] : path2) seed[oid(cx,cy)] = 1;\n                makeCandidate(seed, (cfgId < 4 ? 0.030 : 0.020));\n            }\n        }\n\n        // prune to keep time stable\n        if ((int)cands.size() > 55) {\n            nth_element(cands.begin(), cands.begin()+40, cands.end(),\n                        [](const OccCand& a, const OccCand& b){ return a.approx > b.approx; });\n            cands.resize(40);\n        }\n    }\n\n    // sort by approx\n    sort(cands.begin(), cands.end(), [](const OccCand& a, const OccCand& b){ return a.approx > b.approx; });\n\n    // pre-evaluate top few without intensification (cheap safeguard)\n    int preEval = min(10, (int)cands.size());\n    for (int i = 0; i < preEval && elapsedSec() < 1.90; i++) {\n        int cfgId = cands[i].cfgId;\n        if (!extractBoundaryPolygon(cfgs[cfgId], cands[i].occ, polyTmp)) continue;\n        if (!validOutputBasic(polyTmp)) continue;\n        int d = evalPolygonDiff(pts, polyTmp);\n        if (d > bestDiff) { bestDiff = d; bestPoly = polyTmp; }\n    }\n\n    // intensify top-K candidates\n    int refineK = min(10, (int)cands.size());\n    for (int i = 0; i < refineK && elapsedSec() < 1.985; i++) {\n        int cfgId = cands[i].cfgId;\n        const auto& cfg = cfgs[cfgId];\n        auto& wgrid = wgrids[cfgId];\n\n        Polyomino P;\n        P.occ = cands[i].occ;\n        P.boundaryEdges = computeBoundaryEdges(P.occ);\n        P.totalW = computeTotalW(P.occ, wgrid);\n\n        double rem = 1.985 - elapsedSec();\n        double budget = max(0.010, rem / (refineK - i));\n        double tEnd = min(1.985, elapsedSec() + budget);\n        localImprovePolyomino(P, cfg, wgrid, rng, tEnd, elapsedSec);\n\n        if (!extractBoundaryPolygon(cfg, P.occ, polyTmp)) continue;\n        if (!validOutputBasic(polyTmp)) continue;\n        int d = evalPolygonDiff(pts, polyTmp);\n        if (d > bestDiff) { bestDiff = d; bestPoly = polyTmp; }\n    }\n\n    // fallback if negative\n    if (bestDiff < 0) {\n        Rect empty{0,1,0,1};\n        for (int tries = 0; tries < 5000; tries++) {\n            int x1 = rng.nextInt(0, MAXC-1);\n            int y1 = rng.nextInt(0, MAXC-1);\n            Rect r{x1, x1+1, y1, y1+1};\n            if (!containsAnyRect(pts, r)) { empty = r; break; }\n        }\n        bestPoly = {{empty.x1,empty.y1},{empty.x2,empty.y1},{empty.x2,empty.y2},{empty.x1,empty.y2}};\n    }\n\n    if (!validOutputBasic(bestPoly)) bestPoly = {{0,0},{MAXC,0},{MAXC,MAXC},{0,MAXC}};\n\n    cout << bestPoly.size() << \"\\n\";\n    for (auto [x,y] : bestPoly) cout << x << \" \" << y << \"\\n\";\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Plan {\n    vector<Op> ops;\n    long long score1 = (1LL<<62); // predicted W+H\n    long long score2 = (1LL<<62); // predicted W+H + balance proxy\n    int m = -1;                   // prefix column count if applicable\n    long long margin = 0;\n    string tag;\n};\n\nstruct OnlineParam{\n    long long openBias;\n    long long margin;\n    int headerMode;   // 0 wide, 1 narrow, 2 local\n    int penType;      // 0 linear, 1 square\n    int penShift;     // shift for penalty\n    int targetK;      // -1 none\n    long long kCoef;\n};\n\nstruct Scheduled {\n    Plan plan;\n    bool hasParam = false;\n    OnlineParam param{};\n};\n\nusing Arr2 = array<long long,2>;\n\nstatic inline uint64_t hash_plan_ops(const vector<Op>& ops){\n    uint64_t x = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v){\n        x ^= v;\n        x *= 1099511628211ULL;\n    };\n    for(const auto& op: ops){\n        mix((uint64_t)op.p);\n        mix((uint64_t)op.r);\n        mix((uint64_t)op.d);\n        mix((uint64_t)(op.b + 7));\n    }\n    return x;\n}\n\nstatic inline pair<long long,long long> dims_ll(long long w, long long h, int r){\n    return (r==0) ? make_pair(w,h) : make_pair(h,w);\n}\n\nstatic inline long long pen_val(long long x, int penType, int penShift){\n    if(penShift <= 0) return 0;\n    if(penType == 0) return (x >> penShift);\n    __int128 v = (__int128)x * x;\n    v >>= penShift;\n    if(v > (__int128)LLONG_MAX/4) return (1LL<<60);\n    return (long long)v;\n}\n\n// -------------------- Baselines / Shelves --------------------\n\nPlan make_single_row(const vector<long long>& w, const vector<long long>& h, bool wide){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n    long long W=0, H=0;\n    for(int i=0;i<N;i++){\n        int r = wide ? ((w[i] < h[i]) ? 1 : 0) : ((w[i] > h[i]) ? 1 : 0);\n        auto [ww,hh] = dims_ll(w[i],h[i],r);\n        pl.ops.push_back({i,r,'L',-1});\n        W += ww;\n        H = max(H, hh);\n    }\n    pl.score1 = pl.score2 = W + H;\n    pl.tag = wide ? \"single_row_wide\" : \"single_row_narrow\";\n    return pl;\n}\n\n// Contiguous shelf rows (robust diversity)\nPlan make_shelf_rows_width_limit(const vector<long long>& w, const vector<long long>& h, long long M){\n    int N = (int)w.size();\n    Plan pl;\n    pl.ops.reserve(N);\n\n    long long totalH = 0, maxW = 0;\n    int prevRowRep = -1;\n    long long curW = 0, curH = 0;\n    int curRep = -1;\n\n    auto close_row = [&](){\n        if(curRep==-1) return;\n        totalH += curH;\n        maxW = max(maxW, curW);\n        prevRowRep = curRep;\n        curW = 0; curH = 0; curRep = -1;\n    };\n\n    for(int i=0;i<N;i++){\n        auto [w0,h0] = dims_ll(w[i],h[i],0);\n        auto [w1,h1] = dims_ll(w[i],h[i],1);\n\n        auto can_add = [&](long long ww)->bool{\n            if(curRep==-1) return true;\n            return curW + ww <= M;\n        };\n        bool fit0 = can_add(w0), fit1 = can_add(w1);\n\n        if(curRep!=-1 && !fit0 && !fit1){\n            close_row();\n            fit0 = fit1 = true;\n        }\n\n        int r;\n        if(curRep==-1){\n            if(h0 != h1) r = (h0 < h1 ? 0 : 1);\n            else r = (w0 < w1 ? 0 : 1);\n        }else{\n            if(fit0 && fit1){\n                long long nh0 = max(curH, h0), nh1 = max(curH, h1);\n                if(nh0 != nh1) r = (nh0 < nh1 ? 0 : 1);\n                else r = (w0 < w1 ? 0 : 1);\n            }else r = fit0 ? 0 : 1;\n        }\n\n        auto [ww,hh] = dims_ll(w[i],h[i],r);\n        int b = (prevRowRep==-1 ? -1 : prevRowRep);\n        pl.ops.push_back({i,r,'L',b});\n        curW += ww;\n        if(curRep==-1 || hh > curH){\n            curH = hh;\n            curRep = i;\n        }\n    }\n    close_row();\n\n    pl.score1 = pl.score2 = maxW + totalH;\n    pl.tag = \"shelf_M=\" + to_string(M);\n    return pl;\n}\n\n// -------------------- Prefix BF (columns) --------------------\n\nstatic inline vector<int> order_height(int N, int m, const vector<Arr2>& wr, const vector<Arr2>& hr){\n    vector<int> idx; idx.reserve(N-m);\n    for(int i=m;i<N;i++) idx.push_back(i);\n    sort(idx.begin(), idx.end(), [&](int a, int b){\n        long long Ha = max(hr[a][0], hr[a][1]), Hb = max(hr[b][0], hr[b][1]);\n        if(Ha != Hb) return Ha > Hb;\n        long long Wa = max(wr[a][0], wr[a][1]), Wb = max(wr[b][0], wr[b][1]);\n        if(Wa != Wb) return Wa > Wb;\n        return a < b;\n    });\n    return idx;\n}\nstatic inline vector<int> order_width(int N, int m, const vector<Arr2>& wr, const vector<Arr2>& hr){\n    vector<int> idx; idx.reserve(N-m);\n    for(int i=m;i<N;i++) idx.push_back(i);\n    sort(idx.begin(), idx.end(), [&](int a, int b){\n        long long Wa = max(wr[a][0], wr[a][1]), Wb = max(wr[b][0], wr[b][1]);\n        if(Wa != Wb) return Wa > Wb;\n        long long Ha = max(hr[a][0], hr[a][1]), Hb = max(hr[b][0], hr[b][1]);\n        if(Ha != Hb) return Ha > Hb;\n        return a < b;\n    });\n    return idx;\n}\nstatic inline vector<int> order_area(int N, int m, const vector<Arr2>& wr, const vector<Arr2>& hr){\n    vector<int> idx; idx.reserve(N-m);\n    for(int i=m;i<N;i++) idx.push_back(i);\n    sort(idx.begin(), idx.end(), [&](int a, int b){\n        long long wa = max(wr[a][0], wr[a][1]), ha = max(hr[a][0], hr[a][1]);\n        long long wb = max(wr[b][0], wr[b][1]), hb = max(hr[b][0], hr[b][1]);\n        __int128 Aa = (__int128)wa * ha;\n        __int128 Ab = (__int128)wb * hb;\n        if(Aa != Ab) return Aa > Ab;\n        if(ha != hb) return ha > hb;\n        return a < b;\n    });\n    return idx;\n}\n\nPlan make_prefix_bf_multiorder(const vector<Arr2>& wr, const vector<Arr2>& hr,\n                               int m, long long margin,\n                               const vector<vector<int>>& orders)\n{\n    int N = (int)wr.size();\n    Plan best; best.score1 = best.score2 = (1LL<<62);\n    if(m<=0 || m>N) return best;\n\n    int lim = 1<<m;\n    vector<int> bestCol(N,-1), bestRot(N,0);\n\n    vector<int> colOf(N,-1), rotOf(N,0);\n    vector<long long> colW(m), colH(m);\n\n    for(int mask=0; mask<lim; mask++){\n        long long totalW=0, baseMaxH=0;\n        for(int j=0;j<m;j++){\n            int r = (mask>>j)&1;\n            colW[j] = wr[j][r];\n            colH[j] = hr[j][r];\n            totalW += colW[j];\n            baseMaxH = max(baseMaxH, colH[j]);\n            colOf[j]=j;\n            rotOf[j]=r;\n        }\n\n        long long bestMaskScore1 = (1LL<<62);\n        long long bestMaskScore2 = (1LL<<62);\n        vector<int> bestMaskCol, bestMaskRot;\n\n        for(const auto& ord: orders){\n            vector<long long> H = colH;\n            for(int i=m;i<N;i++){ colOf[i]=-1; rotOf[i]=0; }\n            long long maxH = baseMaxH;\n            bool ok = true;\n\n            for(int idx: ord){\n                long long bestObj = (1LL<<62), bestNewH = (1LL<<62), bestSlack = (1LL<<62);\n                int bestJ=-1, bestR=0;\n                for(int j=0;j<m;j++){\n                    for(int r=0;r<=1;r++){\n                        long long ww = wr[idx][r];\n                        if(ww + margin > colW[j]) continue;\n                        long long hh = hr[idx][r];\n                        long long newH = H[j] + hh;\n                        long long slack = colW[j] - ww;\n                        long long obj = totalW + max(maxH, newH);\n                        if(obj < bestObj ||\n                           (obj==bestObj && newH < bestNewH) ||\n                           (obj==bestObj && newH==bestNewH && slack < bestSlack))\n                        {\n                            bestObj=obj; bestNewH=newH; bestSlack=slack;\n                            bestJ=j; bestR=r;\n                        }\n                    }\n                }\n                if(bestJ==-1){ ok=false; break; }\n                colOf[idx]=bestJ;\n                rotOf[idx]=bestR;\n                H[bestJ] += hr[idx][bestR];\n                maxH = max(maxH, H[bestJ]);\n            }\n            if(!ok) continue;\n\n            long long score1 = totalW + maxH;\n            long long sumSq = 0;\n            for(int j=0;j<m;j++) sumSq += H[j]*H[j];\n            long long score2 = score1 + (sumSq >> 10);\n\n            if(score1 < bestMaskScore1 || (score1==bestMaskScore1 && score2 < bestMaskScore2)){\n                bestMaskScore1 = score1;\n                bestMaskScore2 = score2;\n                bestMaskCol = colOf;\n                bestMaskRot = rotOf;\n            }\n        }\n\n        if(bestMaskScore1 < best.score1 || (bestMaskScore1==best.score1 && bestMaskScore2 < best.score2)){\n            best.score1 = bestMaskScore1;\n            best.score2 = bestMaskScore2;\n            bestCol = std::move(bestMaskCol);\n            bestRot = std::move(bestMaskRot);\n        }\n    }\n\n    if(best.score1 >= (1LL<<61)) return best;\n\n    best.ops.reserve(N);\n    for(int i=0;i<N;i++){\n        int r = bestRot[i];\n        if(i < m){\n            best.ops.push_back({i,r,'L',-1});\n        }else{\n            int c = bestCol[i];\n            int b = (c==0 ? -1 : (c-1));\n            best.ops.push_back({i,r,'U',b});\n        }\n    }\n    best.m = m;\n    best.margin = margin;\n    best.tag = \"prefix\";\n    return best;\n}\n\n// -------------------- Online columns --------------------\n\nstatic Scheduled make_online_columns(const vector<Arr2>& wr,\n                                     const vector<Arr2>& hr,\n                                     const OnlineParam& prm,\n                                     uint64_t seed)\n{\n    int N = (int)wr.size();\n    mt19937_64 rng(seed);\n\n    struct Col{ long long W,H; int headerIdx; };\n    vector<Col> cols; cols.reserve(64);\n    vector<int> headers; headers.reserve(64);\n    vector<Op> ops; ops.reserve(N);\n\n    long long totalW=0, maxH=0;\n\n    auto header_rot = [&](int i)->int{\n        if(prm.headerMode==0) return (wr[i][0] < wr[i][1]) ? 1 : 0; // wide\n        if(prm.headerMode==1) return (wr[i][0] > wr[i][1]) ? 1 : 0; // narrow\n        long long o0 = (totalW + wr[i][0]) + max(maxH, hr[i][0]);\n        long long o1 = (totalW + wr[i][1]) + max(maxH, hr[i][1]);\n        if(o0 != o1) return (o0 < o1 ? 0 : 1);\n        return (wr[i][0] < wr[i][1] ? 0 : 1);\n    };\n\n    auto open_extra = [&](int curK)->long long{\n        if(prm.targetK < 0) return 0;\n        return prm.kCoef * (long long)(curK - prm.targetK);\n    };\n\n    for(int i=0;i<N;i++){\n        if(cols.empty()){\n            int r = header_rot(i);\n            cols.push_back({wr[i][r], hr[i][r], i});\n            headers.push_back(i);\n            totalW += wr[i][r];\n            maxH = max(maxH, hr[i][r]);\n            ops.push_back({i,r,'L',-1});\n            continue;\n        }\n\n        long long bestObj = (1LL<<62), bestNewH=(1LL<<62), bestSlack=(1LL<<62);\n        int bestC=-1, bestR=0;\n\n        for(int c=0;c<(int)cols.size();c++){\n            for(int r=0;r<=1;r++){\n                long long ww = wr[i][r], hh = hr[i][r];\n                if(ww + prm.margin > cols[c].W) continue;\n                long long newH = cols[c].H + hh;\n                long long slack = cols[c].W - ww;\n                long long obj = totalW + max(maxH, newH) + pen_val(newH, prm.penType, prm.penShift);\n                if(obj < bestObj ||\n                   (obj==bestObj && newH < bestNewH) ||\n                   (obj==bestObj && newH==bestNewH && slack < bestSlack))\n                {\n                    bestObj=obj; bestNewH=newH; bestSlack=slack;\n                    bestC=c; bestR=r;\n                }else if(obj==bestObj && ((rng()&31ULL)==0ULL)){\n                    bestC=c; bestR=r;\n                }\n            }\n        }\n\n        int hr0 = header_rot(i);\n        int hr1 = hr0 ^ 1;\n        long long openObj0 = (totalW + wr[i][hr0]) + max(maxH, hr[i][hr0])\n                           + pen_val(hr[i][hr0], prm.penType, prm.penShift)\n                           + prm.openBias + open_extra((int)cols.size());\n        long long openObj1 = (totalW + wr[i][hr1]) + max(maxH, hr[i][hr1])\n                           + pen_val(hr[i][hr1], prm.penType, prm.penShift)\n                           + prm.openBias + open_extra((int)cols.size());\n        int openR = (openObj1 < openObj0 ? hr1 : hr0);\n        long long openObj = min(openObj0, openObj1);\n\n        bool doOpen = false;\n        if(bestC==-1) doOpen=true;\n        else if(openObj < bestObj) doOpen=true;\n        else if(openObj==bestObj && ((rng()&3ULL)==0ULL)) doOpen=true;\n\n        if(doOpen){\n            cols.push_back({wr[i][openR], hr[i][openR], i});\n            headers.push_back(i);\n            totalW += wr[i][openR];\n            maxH = max(maxH, hr[i][openR]);\n            ops.push_back({i,openR,'L',-1});\n        }else{\n            cols[bestC].H += hr[i][bestR];\n            maxH = max(maxH, cols[bestC].H);\n            int b = (bestC==0 ? -1 : headers[bestC-1]);\n            ops.push_back({i,bestR,'U',b});\n        }\n    }\n\n    long long sumSq=0;\n    for(auto &c: cols) sumSq += c.H*c.H;\n\n    Scheduled out;\n    out.hasParam = true;\n    out.param = prm;\n    out.plan.ops = std::move(ops);\n    out.plan.score1 = totalW + maxH;\n    out.plan.score2 = out.plan.score1 + (sumSq >> 10);\n    out.plan.tag = \"online\";\n    return out;\n}\n\n// -------------------- Adaptive stats --------------------\n\nstruct ParamStat{\n    OnlineParam p;\n    long long bestMeas = (1LL<<62);\n    long double avgMeas = 0;\n    int cnt = 0;\n};\nstatic bool same_param(const OnlineParam& a, const OnlineParam& b){\n    return a.openBias==b.openBias && a.margin==b.margin && a.headerMode==b.headerMode &&\n           a.penType==b.penType && a.penShift==b.penShift && a.targetK==b.targetK;\n}\nstatic long double rank_value(const ParamStat& st){\n    if(st.cnt<=1) return (long double)st.bestMeas;\n    return st.avgMeas;\n}\n\n// -------------------- Exploration policy (sigma-aware) --------------------\n\nstatic int decide_explore_turns(int N, int T, long long sigma){\n    if(T < 30) return 0;\n    if(sigma <= 2500) return 0; // small noise -> exploration often not worth it\n    int E = 2 + (T - 30) / 7;    // T=50 ->4, T=80 ->7\n    if(sigma >= 7000) E += 1;    // slightly more when very noisy\n    E = min(E, 8);\n    E = min(E, max(0, T - 15)); // keep >=15 packing turns\n    E = min(E, max(0, N/3));\n    return max(0, E);\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    long long sigma;\n    cin >> N >> T >> sigma;\n\n    vector<long long> wobs(N), hobs(N);\n    for(int i=0;i<N;i++) cin >> wobs[i] >> hobs[i];\n\n    int E = decide_explore_turns(N, T, sigma);\n\n    // robust running means (start from observation)\n    vector<long double> muW(N), muH(N);\n    vector<int> cnt(N, 1);\n    for(int i=0;i<N;i++){\n        muW[i] = (long double)wobs[i];\n        muH[i] = (long double)hobs[i];\n    }\n\n    // choose exploration targets: mix likely headers and global large\n    vector<int> pick;\n    pick.reserve(E);\n    unordered_set<int> used;\n    used.reserve(E*2+10);\n\n    int headerCand = min(N, 15);\n    vector<int> headIdx(headerCand);\n    iota(headIdx.begin(), headIdx.end(), 0);\n    sort(headIdx.begin(), headIdx.end(), [&](int a, int b){\n        long long sa = wobs[a] + hobs[a];\n        long long sb = wobs[b] + hobs[b];\n        if(sa != sb) return sa > sb;\n        return a < b;\n    });\n\n    vector<int> allIdx(N);\n    iota(allIdx.begin(), allIdx.end(), 0);\n    sort(allIdx.begin(), allIdx.end(), [&](int a, int b){\n        long long sa = wobs[a] + hobs[a];\n        long long sb = wobs[b] + hobs[b];\n        if(sa != sb) return sa > sb;\n        return a < b;\n    });\n\n    int half = E/2;\n    for(int i=0;i<(int)headIdx.size() && (int)pick.size() < half; i++){\n        int id = headIdx[i];\n        if(used.insert(id).second) pick.push_back(id);\n    }\n    for(int i=0;i<N && (int)pick.size() < E; i++){\n        int id = allIdx[i];\n        if(used.insert(id).second) pick.push_back(id);\n    }\n\n    // Robust update: FIXED BUG (increment count ONCE per exploration)\n    auto robust_update = [&](int id, long long Wp, long long Hp){\n        long double clip = (long double)3.0 * (long double)sigma;\n        int c = cnt[id]; // old count\n        auto clip_to = [&](long double mu, long long x)->long double{\n            long double lo = mu - clip;\n            long double hi = mu + clip;\n            long double xx = (long double)x;\n            if(xx < lo) xx = lo;\n            if(xx > hi) xx = hi;\n            return xx;\n        };\n        long double wcl = clip_to(muW[id], Wp);\n        long double hcl = clip_to(muH[id], Hp);\n        muW[id] = (muW[id] * (long double)c + wcl) / (long double)(c + 1);\n        muH[id] = (muH[id] * (long double)c + hcl) / (long double)(c + 1);\n        cnt[id] = c + 1;\n    };\n\n    // Exploration turns: measure one rectangle alone (r=0, L -1) => W'=w, H'=h with noise\n    for(int t=0;t<E;t++){\n        int id = pick[t];\n        cout << 1 << '\\n';\n        cout << id << ' ' << 0 << ' ' << 'L' << ' ' << -1 << '\\n';\n        cout.flush();\n        long long Wp, Hp;\n        cin >> Wp >> Hp;\n        robust_update(id, Wp, Hp);\n    }\n\n    int T2 = T - E;\n    if(T2 <= 0) return 0;\n\n    // Updated estimates\n    vector<long long> w(N), h(N);\n    for(int i=0;i<N;i++){\n        long long wi = (long long) llround(muW[i]);\n        long long hi = (long long) llround(muH[i]);\n        w[i] = max(1LL, wi);\n        h[i] = max(1LL, hi);\n    }\n\n    vector<Arr2> wr(N), hr(N);\n    for(int i=0;i<N;i++){\n        wr[i][0]=w[i]; hr[i][0]=h[i];\n        wr[i][1]=h[i]; hr[i][1]=w[i];\n    }\n\n    long long marginHalf = sigma/2;\n    long long scale = max(20000LL, sigma * 6);\n\n    // Prefix plans m<=13\n    vector<Plan> prefixPlans;\n    int Mmax = min(N, 13);\n    for(int m=2;m<=Mmax;m++){\n        vector<vector<int>> orders;\n        orders.push_back(order_height(N,m,wr,hr));\n        orders.push_back(order_width(N,m,wr,hr));\n        orders.push_back(order_area(N,m,wr,hr));\n        {\n            Plan p0 = make_prefix_bf_multiorder(wr, hr, m, 0, orders);\n            if((int)p0.ops.size()==N) prefixPlans.push_back(std::move(p0));\n        }\n        {\n            Plan p1 = make_prefix_bf_multiorder(wr, hr, m, marginHalf, orders);\n            if((int)p1.ops.size()==N) prefixPlans.push_back(std::move(p1));\n        }\n    }\n    sort(prefixPlans.begin(), prefixPlans.end(), [](const Plan& a, const Plan& b){\n        if(a.score1 != b.score1) return a.score1 < b.score1;\n        if(a.m != b.m) return a.m < b.m;\n        return a.margin < b.margin;\n    });\n\n    unordered_map<int, Plan> bestByM;\n    for(const auto& p : prefixPlans){\n        if(p.margin != 0) continue;\n        if(!bestByM.count(p.m) || p.score1 < bestByM[p.m].score1) bestByM[p.m] = p;\n    }\n\n    // Anchors\n    vector<Scheduled> anchors;\n    anchors.push_back({make_single_row(w,h,true), false, {}});\n    anchors.push_back({make_single_row(w,h,false), false, {}});\n\n    long double area = 0;\n    for(int i=0;i<N;i++) area += (long double)w[i] * (long double)h[i];\n    long long base = (long long) llround(sqrt((long double)max((long double)1.0, area)));\n    for(long long mul10 : {9LL, 11LL, 13LL, 15LL, 18LL}){\n        anchors.push_back({make_shelf_rows_width_limit(w,h, max(1LL, base*mul10/10)), false, {}});\n    }\n    for(int i=0;i<min(6, (int)prefixPlans.size()); i++){\n        anchors.push_back({prefixPlans[i], false, {}});\n    }\n    for(int m : {4,6,8,10,12,13}){\n        if(bestByM.count(m)) anchors.push_back({bestByM[m], false, {}});\n    }\n\n    // tiny deterministic online anchors (few)\n    {\n        uint64_t seed0 = 424242ULL;\n        vector<Scheduled> grid;\n        for(long long b : {-3*scale, -scale, 0LL, scale, 3*scale}){\n            OnlineParam prm;\n            prm.openBias = b;\n            prm.margin = 0;\n            prm.headerMode = 2;\n            prm.penType = 0;\n            prm.penShift = 4;\n            prm.targetK = -1;\n            prm.kCoef = scale/3;\n            grid.push_back(make_online_columns(wr, hr, prm, seed0++));\n        }\n        sort(grid.begin(), grid.end(), [](const Scheduled& a, const Scheduled& b){\n            return a.plan.score1 < b.plan.score1;\n        });\n        for(int i=0;i<min(3, (int)grid.size()); i++) anchors.push_back(grid[i]);\n    }\n\n    // Dedup anchors\n    {\n        vector<Scheduled> tmp;\n        tmp.reserve(anchors.size());\n        unordered_set<uint64_t> seen;\n        seen.reserve(anchors.size()*2);\n        for(auto &sc : anchors){\n            if((int)sc.plan.ops.size()!=N) continue;\n            uint64_t hv = hash_plan_ops(sc.plan.ops);\n            if(seen.insert(hv).second) tmp.push_back(std::move(sc));\n        }\n        anchors.swap(tmp);\n        sort(anchors.begin(), anchors.end(), [](const Scheduled& a, const Scheduled& b){\n            if(a.plan.score1 != b.plan.score1) return a.plan.score1 < b.plan.score1;\n            return a.plan.tag < b.plan.tag;\n        });\n    }\n\n    int A = min((int)anchors.size(), min(14, max(6, T2/3)));\n\n    // Random pool (mid phase)\n    mt19937_64 rng(123456789ULL);\n    auto rnd_ll = [&](long long L, long long R)->long long{\n        uint64_t x = rng();\n        return L + (long long)(x % (uint64_t)(R - L + 1));\n    };\n\n    int R = min(3200, max(1200, T2*10));\n    vector<Scheduled> rndPool;\n    rndPool.reserve(R);\n    for(int i=0;i<R;i++){\n        OnlineParam prm;\n        prm.openBias = rnd_ll(-3*scale, 3*scale);\n        prm.margin = ((rng()&1ULL) ? 0 : marginHalf);\n        prm.headerMode = (int)(rng()%3);\n        prm.penType = (int)(rng()%6==0 ? 1 : 0);\n        prm.penShift = (prm.penType==0 ? (int)rnd_ll(3,6) : (int)rnd_ll(20,23));\n        prm.targetK = ((rng()%3)==0 ? -1 : (int)rnd_ll(5,22));\n        prm.kCoef = scale/3;\n\n        uint64_t seed = 777777ULL + (uint64_t)i*1000003ULL + (rng()&0xFFFFULL);\n        rndPool.push_back(make_online_columns(wr, hr, prm, seed));\n    }\n\n    // Dedup rndPool\n    {\n        vector<Scheduled> tmp;\n        tmp.reserve(rndPool.size());\n        unordered_set<uint64_t> seen;\n        seen.reserve(rndPool.size()*2);\n        for(auto &sc: rndPool){\n            uint64_t hv = hash_plan_ops(sc.plan.ops);\n            if(seen.insert(hv).second) tmp.push_back(std::move(sc));\n        }\n        rndPool.swap(tmp);\n    }\n\n    vector<int> ord1(rndPool.size()), ord2(rndPool.size()), ord3(rndPool.size());\n    iota(ord1.begin(), ord1.end(), 0);\n    iota(ord2.begin(), ord2.end(), 0);\n    iota(ord3.begin(), ord3.end(), 0);\n    sort(ord1.begin(), ord1.end(), [&](int a, int b){ return rndPool[a].plan.score1 < rndPool[b].plan.score1; });\n    sort(ord2.begin(), ord2.end(), [&](int a, int b){ return rndPool[a].plan.score2 < rndPool[b].plan.score2; });\n    shuffle(ord3.begin(), ord3.end(), rng);\n\n    int remain = T2 - A;\n    int S_mid = min(remain, 50);\n    vector<Scheduled> mid;\n    mid.reserve(S_mid);\n\n    unordered_set<uint64_t> usedMid;\n    usedMid.reserve((size_t)S_mid*3);\n    size_t p1=0,p2=0,p3=0;\n    while((int)mid.size() < S_mid){\n        for(int sel=0; sel<3 && (int)mid.size() < S_mid; sel++){\n            int idx=-1;\n            if(sel==0){\n                while(p1<ord1.size()){\n                    int c=ord1[p1++];\n                    uint64_t hv = hash_plan_ops(rndPool[c].plan.ops);\n                    if(usedMid.insert(hv).second){ idx=c; break; }\n                }\n            }else if(sel==1){\n                while(p2<ord2.size()){\n                    int c=ord2[p2++];\n                    uint64_t hv = hash_plan_ops(rndPool[c].plan.ops);\n                    if(usedMid.insert(hv).second){ idx=c; break; }\n                }\n            }else{\n                while(p3<ord3.size()){\n                    int c=ord3[p3++];\n                    uint64_t hv = hash_plan_ops(rndPool[c].plan.ops);\n                    if(usedMid.insert(hv).second){ idx=c; break; }\n                }\n            }\n            if(idx!=-1) mid.push_back(rndPool[idx]);\n        }\n        if(p1>=ord1.size() && p2>=ord2.size() && p3>=ord3.size()) break;\n    }\n    while((int)mid.size() < S_mid && !ord1.empty()){\n        mid.push_back(rndPool[ord1[mid.size() % ord1.size()]]);\n    }\n\n    // Adaptive stats\n    vector<ParamStat> bestParams;\n    bestParams.reserve(24);\n    auto update_best = [&](const OnlineParam& p, long long meas){\n        for(auto &st: bestParams){\n            if(same_param(st.p, p)){\n                st.bestMeas = min(st.bestMeas, meas);\n                st.avgMeas = (st.avgMeas * (long double)st.cnt + (long double)meas) / (long double)(st.cnt + 1);\n                st.cnt++;\n                goto resort;\n            }\n        }\n        {\n            ParamStat st;\n            st.p = p; st.bestMeas = meas; st.avgMeas = (long double)meas; st.cnt = 1;\n            bestParams.push_back(st);\n        }\n        resort:\n        sort(bestParams.begin(), bestParams.end(), [](const ParamStat& a, const ParamStat& b){\n            long double ra = rank_value(a), rb = rank_value(b);\n            if(ra != rb) return ra < rb;\n            return a.bestMeas < b.bestMeas;\n        });\n        if((int)bestParams.size() > 16) bestParams.resize(16);\n    };\n\n    long long lastW=-1, lastH=-1;\n\n    // Main packing loop\n    for(int t=0;t<T2;t++){\n        Scheduled out;\n        out.hasParam = false;\n\n        if(t < A){\n            out = anchors[t];\n        }else if(t < A + (int)mid.size()){\n            out = mid[t - A];\n        }else{\n            OnlineParam prm;\n            bool exploit = (!bestParams.empty() && ((rng()%100) < 70));\n            if(exploit){\n                int pick = 0;\n                uint64_t r = rng() & 1023ULL;\n                if((int)bestParams.size() >= 2 && r < 300) pick = 1;\n                if((int)bestParams.size() >= 3 && r < 120) pick = 2;\n                if((int)bestParams.size() >= 4 && r < 50)  pick = 3;\n                prm = bestParams[pick].p;\n\n                prm.openBias += rnd_ll(-scale, scale);\n                if((rng()&15ULL)==0ULL) prm.margin = (prm.margin==0 ? marginHalf : 0);\n                if((rng()&31ULL)==0ULL) prm.headerMode = (prm.headerMode + 1 + (int)(rng()%2))%3;\n                if((rng()&31ULL)==0ULL) prm.penType ^= 1;\n                prm.penShift = (prm.penType==0 ? (int)rnd_ll(3,6) : (int)rnd_ll(20,23));\n                if((rng()&15ULL)==0ULL){\n                    if(prm.targetK<0) prm.targetK = (int)rnd_ll(6,20);\n                    else if((rng()&1ULL)) prm.targetK = -1;\n                    else prm.targetK = (int)max(5LL, min(22LL, (long long)prm.targetK + rnd_ll(-2,2)));\n                }\n                prm.kCoef = scale/3;\n            }else{\n                prm.openBias = rnd_ll(-3*scale, 3*scale);\n                prm.margin = ((rng()&1ULL) ? 0 : marginHalf);\n                prm.headerMode = (int)(rng()%3);\n                prm.penType = (int)(rng()%6==0 ? 1 : 0);\n                prm.penShift = (prm.penType==0 ? (int)rnd_ll(3,6) : (int)rnd_ll(20,23));\n                prm.targetK = ((rng()%3)==0 ? -1 : (int)rnd_ll(5,22));\n                prm.kCoef = scale/3;\n            }\n\n            if(lastW>0 && lastH>0){\n                if(lastW > lastH*12/10) prm.openBias += scale/2;\n                else if(lastH > lastW*12/10) prm.openBias -= scale/2;\n            }\n\n            uint64_t seed = 999000ULL + (uint64_t)(t+E)*1000003ULL + (rng()&0xFFFFULL);\n            out = make_online_columns(wr, hr, prm, seed);\n        }\n\n        cout << out.plan.ops.size() << '\\n';\n        for(const auto& op: out.plan.ops){\n            cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        long long Wp, Hp;\n        if(!(cin >> Wp >> Hp)) break;\n        lastW = Wp; lastH = Hp;\n\n        if(out.hasParam){\n            update_best(out.param, Wp + Hp);\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 1000;\nstatic const uint8_t INF8 = 255;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed_sec() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Bits {\n    static constexpr int W = (MAXN + 63) / 64;\n    array<uint64_t, W> a{};\n    void reset() { a.fill(0); }\n    void set(int i) { a[i >> 6] |= 1ULL << (i & 63); }\n    bool any() const { for (auto x : a) if (x) return true; return false; }\n};\n\nstatic inline int popcount_and(const Bits &x, const Bits &y) {\n    int s = 0;\n    for (int i = 0; i < Bits::W; i++) s += __builtin_popcountll(x.a[i] & y.a[i]);\n    return s;\n}\nstatic inline void andnot_inplace(Bits &x, const Bits &mask) {\n    for (int i = 0; i < Bits::W; i++) x.a[i] &= ~mask.a[i];\n}\nstatic inline double u01(uint64_t r) {\n    return (r >> 11) * (1.0 / 9007199254740992.0);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, H;\n    cin >> N >> M >> H;\n    vector<int> A(N);\n    for (int i = 0; i < N; i++) cin >> A[i];\n\n    vector<vector<int>> adj(N);\n    vector<bitset<MAXN>> adjbs(N);\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        adjbs[u].set(v);\n        adjbs[v].set(u);\n    }\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        (void)x; (void)y;\n    }\n\n    mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    // Precompute distances up to H (truncated BFS)\n    vector<vector<uint8_t>> dist(N, vector<uint8_t>(N, INF8));\n    {\n        deque<int> q;\n        vector<int> dd(N);\n        for (int s = 0; s < N; s++) {\n            fill(dd.begin(), dd.end(), -1);\n            dd[s] = 0;\n            q.clear();\n            q.push_back(s);\n            while (!q.empty()) {\n                int v = q.front(); q.pop_front();\n                int dv = dd[v];\n                if (dv > H) continue;\n                dist[s][v] = (uint8_t)dv;\n                if (dv == H) continue;\n                for (int to : adj[v]) if (dd[to] == -1) {\n                    dd[to] = dv + 1;\n                    q.push_back(to);\n                }\n            }\n        }\n    }\n\n    vector<Bits> coverMask(N);\n    vector<vector<int>> coverList(N);\n    for (int s = 0; s < N; s++) {\n        coverMask[s].reset();\n        coverList[s].reserve(N);\n        for (int v = 0; v < N; v++) if (dist[s][v] != INF8) {\n            coverMask[s].set(v);\n            coverList[s].push_back(v);\n        }\n    }\n\n    // Root selection: greedy set cover + prune + shift + prune\n    vector<int> roots;\n    {\n        Bits uncovered;\n        uncovered.reset();\n        for (int v = 0; v < N; v++) uncovered.set(v);\n\n        while (uncovered.any()) {\n            int best = -1, bestGain = -1, bestA = 1e9;\n            for (int c = 0; c < N; c++) {\n                int gain = popcount_and(coverMask[c], uncovered);\n                if (gain > bestGain || (gain == bestGain && A[c] < bestA)) {\n                    bestGain = gain;\n                    bestA = A[c];\n                    best = c;\n                }\n            }\n            roots.push_back(best);\n            andnot_inplace(uncovered, coverMask[best]);\n        }\n\n        vector<int> coverCnt(N, 0);\n        int zeroCnt = N;\n        auto add_root = [&](int r) {\n            for (int v : coverList[r]) {\n                if (coverCnt[v] == 0) zeroCnt--;\n                coverCnt[v]++;\n            }\n        };\n        auto remove_root = [&](int r) {\n            for (int v : coverList[r]) {\n                coverCnt[v]--;\n                if (coverCnt[v] == 0) zeroCnt++;\n            }\n        };\n        for (int r : roots) add_root(r);\n\n        auto prune_once = [&]() -> bool {\n            bool changed = false;\n            sort(roots.begin(), roots.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] > A[j];\n                return i < j;\n            });\n            for (int i = 0; i < (int)roots.size(); ) {\n                int r = roots[i];\n                bool ok = true;\n                for (int v : coverList[r]) if (coverCnt[v] == 1) { ok = false; break; }\n                if (ok) {\n                    remove_root(r);\n                    roots.erase(roots.begin() + i);\n                    changed = true;\n                } else i++;\n            }\n            return changed;\n        };\n        while (prune_once()) {}\n\n        vector<char> isRoot(N, 0);\n        for (int r : roots) isRoot[r] = 1;\n\n        for (int idx = 0; idx < (int)roots.size(); idx++) {\n            int r = roots[idx];\n            vector<int> cand;\n            cand.reserve(30);\n            for (int v = 0; v < N; v++) if (dist[r][v] != INF8 && dist[r][v] <= 2) cand.push_back(v);\n            sort(cand.begin(), cand.end(), [&](int i, int j){\n                if (A[i] != A[j]) return A[i] < A[j];\n                return i < j;\n            });\n            int trials = min<int>(40, cand.size());\n            for (int t = 0; t < trials; t++) {\n                int c = cand[t];\n                if (c == r) break;\n                if (isRoot[c]) continue;\n                remove_root(r);\n                add_root(c);\n                if (zeroCnt == 0) {\n                    isRoot[r] = 0;\n                    isRoot[c] = 1;\n                    roots[idx] = c;\n                    r = c;\n                } else {\n                    remove_root(c);\n                    add_root(r);\n                }\n            }\n        }\n        while (prune_once()) {}\n    }\n\n    // Initial forest: multi-source BFS, tie-break by lower A parent\n    vector<int> parent(N, -2);\n    vector<int> depth(N, (int)1e9);\n    {\n        deque<int> q;\n        for (int r : roots) {\n            parent[r] = -1;\n            depth[r] = 0;\n            q.push_back(r);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (depth[v] == H) continue;\n            for (int to : adj[v]) {\n                int nd = depth[v] + 1;\n                if (nd < depth[to]) {\n                    depth[to] = nd;\n                    parent[to] = v;\n                    q.push_back(to);\n                } else if (nd == depth[to] && parent[to] != -1 && A[v] < A[parent[to]]) {\n                    parent[to] = v;\n                }\n            }\n        }\n        for (int v = 0; v < N; v++) if (parent[v] == -2) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n    }\n\n    // State structures\n    vector<vector<int>> children(N);\n    vector<int> childPos(N, -1);\n\n    vector<int> leaves;\n    vector<int> leafPos(N, -1);\n    vector<char> inLeaves(N, 0);\n\n    vector<int> rootsCur;\n    vector<int> rootPos(N, -1);\n    vector<char> inRoot(N, 0);\n\n    vector<int> subSumA(N, 0), subHeight(N, 0), subSize(N, 1);\n\n    vector<int> buf1, buf2;\n\n    auto build_children = [&](){\n        for (int i = 0; i < N; i++) {\n            children[i].clear();\n            childPos[i] = -1;\n        }\n        for (int v = 0; v < N; v++) if (parent[v] != -1) {\n            int p = parent[v];\n            childPos[v] = (int)children[p].size();\n            children[p].push_back(v);\n        }\n    };\n    auto remove_child = [&](int p, int v){\n        int idx = childPos[v];\n        int last = children[p].back();\n        children[p][idx] = last;\n        childPos[last] = idx;\n        children[p].pop_back();\n        childPos[v] = -1;\n    };\n    auto add_child = [&](int p, int v){\n        childPos[v] = (int)children[p].size();\n        children[p].push_back(v);\n    };\n\n    auto rebuild_roots_leaves = [&](){\n        rootsCur.clear();\n        leaves.clear();\n        fill(inRoot.begin(), inRoot.end(), 0);\n        fill(inLeaves.begin(), inLeaves.end(), 0);\n        fill(rootPos.begin(), rootPos.end(), -1);\n        fill(leafPos.begin(), leafPos.end(), -1);\n\n        for (int v = 0; v < N; v++) {\n            if (parent[v] == -1) {\n                inRoot[v] = 1;\n                rootPos[v] = (int)rootsCur.size();\n                rootsCur.push_back(v);\n            }\n        }\n        for (int v = 0; v < N; v++) {\n            if (children[v].empty()) {\n                inLeaves[v] = 1;\n                leafPos[v] = (int)leaves.size();\n                leaves.push_back(v);\n            }\n        }\n    };\n\n    auto make_root = [&](int v){\n        if (inRoot[v]) return;\n        inRoot[v] = 1;\n        rootPos[v] = (int)rootsCur.size();\n        rootsCur.push_back(v);\n    };\n    auto unmake_root = [&](int v){\n        if (!inRoot[v]) return;\n        int idx = rootPos[v];\n        int last = rootsCur.back();\n        rootsCur[idx] = last;\n        rootPos[last] = idx;\n        rootsCur.pop_back();\n        inRoot[v] = 0;\n        rootPos[v] = -1;\n    };\n\n    auto make_leaf = [&](int v){\n        if (inLeaves[v]) return;\n        inLeaves[v] = 1;\n        leafPos[v] = (int)leaves.size();\n        leaves.push_back(v);\n    };\n    auto unmake_leaf = [&](int v){\n        if (!inLeaves[v]) return;\n        int idx = leafPos[v];\n        int last = leaves.back();\n        leaves[idx] = last;\n        leafPos[last] = idx;\n        leaves.pop_back();\n        inLeaves[v] = 0;\n        leafPos[v] = -1;\n    };\n    auto refresh_leaf = [&](int v){\n        if (children[v].empty()) make_leaf(v);\n        else unmake_leaf(v);\n    };\n\n    auto is_ancestor = [&](int anc, int node) -> bool {\n        int cur = node;\n        for (int step = 0; step <= H + 5 && cur != -1; step++) {\n            if (cur == anc) return true;\n            cur = parent[cur];\n        }\n        return false;\n    };\n\n    auto recalc_node = [&](int v){\n        int sum = A[v];\n        int h = 0;\n        int sz = 1;\n        for (int ch : children[v]) {\n            sum += subSumA[ch];\n            sz += subSize[ch];\n            h = max(h, subHeight[ch] + 1);\n        }\n        subSumA[v] = sum;\n        subHeight[v] = h;\n        subSize[v] = sz;\n    };\n    auto recalc_up = [&](int v){\n        while (v != -1) {\n            int oldS = subSumA[v], oldH = subHeight[v], oldZ = subSize[v];\n            recalc_node(v);\n            if (subSumA[v] == oldS && subHeight[v] == oldH && subSize[v] == oldZ) break;\n            v = parent[v];\n        }\n    };\n    auto init_sub_aggregates = [&](){\n        for (int v = 0; v < N; v++) {\n            subSumA[v] = A[v];\n            subHeight[v] = 0;\n            subSize[v] = 1;\n        }\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; v++) layers[min(depth[v], H)].push_back(v);\n        for (int d = H; d >= 0; d--) {\n            for (int v : layers[d]) {\n                int p = parent[v];\n                if (p != -1) {\n                    subSumA[p] += subSumA[v];\n                    subSize[p] += subSize[v];\n                    subHeight[p] = max(subHeight[p], subHeight[v] + 1);\n                }\n            }\n        }\n    };\n\n    auto collect_subtree = [&](int v, vector<int>& nodes) {\n        nodes.clear();\n        vector<int> st;\n        st.push_back(v);\n        while (!st.empty()) {\n            int x = st.back(); st.pop_back();\n            nodes.push_back(x);\n            for (int ch : children[x]) st.push_back(ch);\n        }\n    };\n\n    auto rebuild_from_parent = [&](const vector<int>& par) -> long long {\n        parent = par;\n        build_children();\n\n        // recompute depth from roots\n        fill(depth.begin(), depth.end(), -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (parent[v] == -1) {\n            depth[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int ch : children[v]) {\n                depth[ch] = depth[v] + 1;\n                q.push_back(ch);\n            }\n        }\n        // safety (shouldn't happen)\n        for (int v = 0; v < N; v++) if (depth[v] == -1) {\n            parent[v] = -1;\n            depth[v] = 0;\n        }\n\n        rebuild_roots_leaves();\n        init_sub_aggregates();\n\n        long long score = 0;\n        for (int v = 0; v < N; v++) score += 1LL * depth[v] * A[v];\n        return score;\n    };\n\n    build_children();\n    rebuild_roots_leaves();\n    init_sub_aggregates();\n\n    long long curScore = 0;\n    for (int v = 0; v < N; v++) curScore += 1LL * depth[v] * A[v];\n    long long bestScore = curScore;\n    vector<int> bestParent = parent;\n\n    auto potential = [&](int v) -> long long {\n        int slack = H - (depth[v] + subHeight[v]);\n        if (slack <= 0) return 0;\n        return 1LL * slack * subSumA[v];\n    };\n    auto selWeight = [&](int v) -> long long {\n        long long p = potential(v);\n        // cost-aware: prefer improvements per subtree size\n        return (p * 1024LL) / (subSize[v] + 32);\n    };\n\n    auto pick_best_among = [&](const vector<int>& pool, int k) -> int {\n        if (pool.empty()) return -1;\n        int best = pool[rng() % pool.size()];\n        long long bestW = selWeight(best);\n        for (int i = 1; i < k; i++) {\n            int v = pool[rng() % pool.size()];\n            long long w = selWeight(v);\n            if (w > bestW) { bestW = w; best = v; }\n        }\n        return best;\n    };\n\n    auto apply_reattach = [&](int v, int u, int delta) {\n        long long deltaScore = 1LL * delta * subSumA[v];\n\n        int oldp = parent[v];\n        if (oldp == -1) unmake_root(v);\n        if (oldp != -1) {\n            remove_child(oldp, v);\n            refresh_leaf(oldp);\n        }\n\n        parent[v] = u;\n        add_child(u, v);\n        refresh_leaf(u);\n\n        if (delta != 0) {\n            collect_subtree(v, buf1);\n            for (int x : buf1) depth[x] += delta;\n        }\n\n        curScore += deltaScore;\n\n        if (oldp != -1) recalc_up(oldp);\n        recalc_up(u);\n    };\n\n    auto try_reattach_SA = [&](int v, int u, double T) -> bool {\n        if (u == v) return false;\n        if (!adjbs[v].test(u)) return false;\n        if (is_ancestor(v, u)) return false;\n\n        int newDepthV = depth[u] + 1;\n        if (newDepthV > H) return false;\n        if (newDepthV + subHeight[v] > H) return false;\n\n        int delta = newDepthV - depth[v];\n        long long deltaScore = 1LL * delta * subSumA[v];\n        if (deltaScore >= 0) {\n            apply_reattach(v, u, delta);\n            return true;\n        }\n\n        if (subSize[v] >= 450) return false;\n        if ((double)(-deltaScore) > 6.0 * T) return false;\n\n        double p = exp((double)deltaScore / T);\n        if (u01(rng()) < p) {\n            apply_reattach(v, u, delta);\n            return true;\n        }\n        return false;\n    };\n\n    auto best_deeper_neighbor = [&](int v) -> int {\n        int bestU = -1, bestD = -1;\n        int limit = H - 1 - subHeight[v];\n        for (int u : adj[v]) {\n            if (depth[u] > limit) continue;\n            int nd = depth[u] + 1;\n            if (nd <= depth[v]) continue;\n            if (is_ancestor(v, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    // Sideways move (delta=0): change parent while keeping same depth\n    auto try_sideways = [&](int v) -> bool {\n        if (parent[v] == -1) return false;\n        int dv = depth[v];\n        int bestU = -1;\n        int bestH = INT_MAX;\n        for (int u : adj[v]) {\n            if (u == parent[v]) continue;\n            if (depth[u] + 1 != dv) continue; // ensures delta=0\n            if (is_ancestor(v, u)) continue;\n            // prefer parent with smaller subtree height to help future shaving/merge flexibility\n            if (subHeight[u] < bestH) {\n                bestH = subHeight[u];\n                bestU = u;\n            }\n        }\n        if (bestU == -1) return false;\n        apply_reattach(v, bestU, 0);\n        return true;\n    };\n\n    auto eval_rotate = [&](int c) -> pair<bool,long long> {\n        int p = parent[c];\n        if (p == -1) return {false, 0};\n        int gp = parent[p];\n        if (gp != -1 && !adjbs[gp].test(c)) return {false, 0};\n\n        int maxAbsOther = depth[p];\n        for (int o : children[p]) if (o != c) {\n            maxAbsOther = max(maxAbsOther, depth[o] + subHeight[o]);\n        }\n        if (maxAbsOther > H - 1) return {false, 0};\n\n        long long gain = 1LL * subSumA[p] - 2LL * subSumA[c];\n        return {true, gain};\n    };\n\n    auto apply_rotate = [&](int c, long long gain) {\n        int p = parent[c];\n        int gp = parent[p];\n\n        collect_subtree(p, buf1);\n        collect_subtree(c, buf2);\n\n        remove_child(p, c);\n        refresh_leaf(p);\n\n        if (gp != -1) {\n            remove_child(gp, p);\n            refresh_leaf(gp);\n            parent[c] = gp;\n            add_child(gp, c);\n            refresh_leaf(gp);\n        } else {\n            parent[c] = -1;\n            make_root(c);\n            unmake_root(p);\n        }\n\n        parent[p] = c;\n        add_child(c, p);\n        refresh_leaf(c);\n\n        for (int x : buf1) depth[x] += 1;\n        for (int x : buf2) depth[x] -= 2;\n\n        curScore += gain;\n\n        recalc_up(p);\n        recalc_up(c);\n        if (gp != -1) recalc_up(gp);\n    };\n\n    auto try_rotate_SA = [&](int c, double T) -> bool {\n        auto [ok, gain] = eval_rotate(c);\n        if (!ok) return false;\n\n        if (gain >= 0) {\n            apply_rotate(c, gain);\n            return true;\n        }\n\n        int p = parent[c];\n        if (p != -1 && subSize[p] >= 600) return false;\n        if ((double)(-gain) > 6.0 * T) return false;\n\n        double pacc = exp((double)gain / T);\n        if (u01(rng()) < pacc) {\n            apply_rotate(c, gain);\n            return true;\n        }\n        return false;\n    };\n\n    auto best_external_neighbor_for_root = [&](int r) -> int {\n        int bestU = -1, bestD = -1;\n        int limit = H - 1 - subHeight[r];\n        for (int u : adj[r]) {\n            if (depth[u] > limit) continue;\n            if (is_ancestor(r, u)) continue;\n            if (depth[u] > bestD) {\n                bestD = depth[u];\n                bestU = u;\n            }\n        }\n        return bestU;\n    };\n\n    auto shave_once = [&](double T) -> bool {\n        if (rootsCur.empty()) return false;\n\n        int r = -1;\n        for (int t = 0; t < 10; t++) {\n            int cand = rootsCur[rng() % rootsCur.size()];\n            if (subHeight[cand] == H) { r = cand; break; }\n            if (r == -1) r = cand;\n        }\n        if (r == -1 || subHeight[r] < H) return false;\n\n        int cur = r;\n        for (int step = 0; step < H; step++) {\n            int nxt = -1;\n            int bestSum = INT_MAX;\n            for (int ch : children[cur]) {\n                if (subHeight[ch] + 1 == subHeight[cur]) {\n                    if (subSumA[ch] < bestSum) {\n                        bestSum = subSumA[ch];\n                        nxt = ch;\n                    }\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        int v = cur;\n\n        int bestU = -1;\n        int bestDepthU = INT_MAX;\n        for (int u : adj[v]) {\n            if (is_ancestor(v, u)) continue;\n            int newDepthV = depth[u] + 1;\n            if (newDepthV + subHeight[v] > H) continue;\n            if (newDepthV >= depth[v]) continue;\n            if (depth[u] < bestDepthU) {\n                bestDepthU = depth[u];\n                bestU = u;\n            }\n        }\n        if (bestU == -1) return false;\n        return try_reattach_SA(v, bestU, T);\n    };\n\n    // Warm-up greedy deepening\n    {\n        vector<int> allNodes(N);\n        iota(allNodes.begin(), allNodes.end(), 0);\n        sort(allNodes.begin(), allNodes.end(), [&](int i, int j){\n            long long wi = selWeight(i), wj = selWeight(j);\n            if (wi != wj) return wi > wj;\n            return A[i] > A[j];\n        });\n        int tries = min(N, 350);\n        for (int t = 0; t < tries; t++) {\n            int v = allNodes[t];\n            for (int rep = 0; rep < 2; rep++) {\n                int u = best_deeper_neighbor(v);\n                if (u == -1) break;\n                (void)try_reattach_SA(v, u, 1e-9);\n            }\n        }\n        if (curScore > bestScore) { bestScore = curScore; bestParent = parent; }\n    }\n\n    // SA with cyclic reheating and restart from best\n    Timer timer;\n    const double TL = 1.98;\n    const double cycles = 3.0;\n    const double cycleLen = TL / cycles;\n    const double T0 = 60000.0;\n    const double T1 = 60.0;\n\n    double nextReset = cycleLen;\n\n    vector<int> allNodes(N);\n    iota(allNodes.begin(), allNodes.end(), 0);\n\n    while (timer.elapsed_sec() < TL) {\n        double elapsed = timer.elapsed_sec();\n\n        if (elapsed >= nextReset) {\n            // restart from best at cycle boundary\n            curScore = rebuild_from_parent(bestParent);\n            nextReset += cycleLen;\n        }\n\n        double cycleStart = floor(elapsed / cycleLen) * cycleLen;\n        double frac = (elapsed - cycleStart) / cycleLen;\n        double T = T0 * pow(T1 / T0, frac);\n\n        int mode = (int)(rng() % 100);\n\n        if (mode < 36) {\n            int v = pick_best_among(leaves, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 56) {\n            int v = pick_best_among(allNodes, 7);\n            if (v == -1) continue;\n            int u = best_deeper_neighbor(v);\n            if (u != -1) (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 70) {\n            // sideways structural move (cheap)\n            int v = pick_best_among(allNodes, 8);\n            if (v == -1) continue;\n            (void)try_sideways(v);\n\n        } else if (mode < 84) {\n            // root merge tournament\n            if (rootsCur.size() <= 1) continue;\n            int bestR = -1, bestU = -1;\n            long long bestGain = -1;\n            for (int t = 0; t < 10; t++) {\n                int rrt = rootsCur[rng() % rootsCur.size()];\n                int u = best_external_neighbor_for_root(rrt);\n                if (u == -1) continue;\n                long long gain = 1LL * (depth[u] + 1) * subSumA[rrt];\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestR = rrt;\n                    bestU = u;\n                }\n            }\n            if (bestR != -1) (void)try_reattach_SA(bestR, bestU, T);\n\n        } else if (mode < 90) {\n            // random reattach (SA)\n            int v = (int)(rng() % N);\n            int u = adj[v][rng() % adj[v].size()];\n            (void)try_reattach_SA(v, u, T);\n\n        } else if (mode < 96) {\n            // rotation best-of-a-few\n            int bestC = -1;\n            long long bestG = LLONG_MIN;\n            for (int t = 0; t < 12; t++) {\n                int p = (int)(rng() % N);\n                if (children[p].empty()) continue;\n                int c = children[p][rng() % children[p].size()];\n                auto [ok, g] = eval_rotate(c);\n                if (!ok) continue;\n                if (g > bestG) { bestG = g; bestC = c; }\n            }\n            if (bestC != -1) (void)try_rotate_SA(bestC, T);\n\n        } else {\n            (void)shave_once(T);\n        }\n\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestParent = parent;\n        }\n    }\n\n    // Final safety repair on bestParent\n    auto repair = [&](vector<int>& par){\n        vector<int> state(N, 0);\n        for (int v = 0; v < N; v++) {\n            if (state[v]) continue;\n            int cur = v;\n            while (cur != -1 && state[cur] == 0) {\n                state[cur] = 1;\n                cur = par[cur];\n            }\n            if (cur != -1 && state[cur] == 1) par[v] = -1;\n            cur = v;\n            while (cur != -1 && state[cur] == 1) {\n                state[cur] = 2;\n                cur = par[cur];\n            }\n        }\n        for (int v = 0; v < N; v++) {\n            if (par[v] == -1) continue;\n            if (!adjbs[v].test(par[v])) par[v] = -1;\n        }\n\n        vector<vector<int>> ch(N);\n        for (int v = 0; v < N; v++) if (par[v] != -1) ch[par[v]].push_back(v);\n\n        vector<int> dep(N, -1);\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (par[v] == -1) {\n            dep[v] = 0;\n            q.push_back(v);\n        }\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            for (int to : ch[v]) {\n                dep[to] = dep[v] + 1;\n                q.push_back(to);\n            }\n        }\n        for (int v = 0; v < N; v++) if (dep[v] == -1) {\n            par[v] = -1;\n            dep[v] = 0;\n        }\n        for (int v = 0; v < N; v++) if (dep[v] > H) par[v] = -1;\n    };\n\n    repair(bestParent);\n\n    for (int i = 0; i < N; i++) {\n        cout << bestParent[i] << (i + 1 == N ? '\\n' : ' ');\n    }\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int G = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr int INF = 1e9;\n\nstatic inline double now_sec() {\n    using namespace std::chrono;\n    static auto st = steady_clock::now();\n    auto t = steady_clock::now() - st;\n    return duration<double>(t).count();\n}\n\nstatic inline int gid(int type, int idx) {\n    // type: 0=Ucol,1=Dcol,2=Lrow,3=Rrow\n    if (type == 0) return idx;\n    if (type == 1) return 20 + idx;\n    if (type == 2) return 40 + idx;\n    return 60 + idx;\n}\n\nstatic inline int rnd_int(std::mt19937_64& rng, int lo, int hi) { // inclusive\n    std::uniform_int_distribution<int> dist(lo, hi);\n    return dist(rng);\n}\nstatic inline double rnd01(std::mt19937_64& rng) {\n    std::uniform_real_distribution<double> dist(0.0, 1.0);\n    return dist(rng);\n}\n\nstruct Board {\n    array<array<char,N>,N> a;\n};\n\nstatic Board read_board(const vector<string>& C) {\n    Board b;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) b.a[i][j] = C[i][j];\n    return b;\n}\n\nstatic int count_x(const Board& b) {\n    int c = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (b.a[i][j] == 'x') c++;\n    return c;\n}\n\nstatic bool apply_move(Board& b, char dir, int p, char &removed) {\n    if (dir == 'L') {\n        removed = b.a[p][0];\n        for (int j = 0; j < N-1; j++) b.a[p][j] = b.a[p][j+1];\n        b.a[p][N-1] = '.';\n    } else if (dir == 'R') {\n        removed = b.a[p][N-1];\n        for (int j = N-1; j >= 1; j--) b.a[p][j] = b.a[p][j-1];\n        b.a[p][0] = '.';\n    } else if (dir == 'U') {\n        removed = b.a[0][p];\n        for (int i = 0; i < N-1; i++) b.a[i][p] = b.a[i+1][p];\n        b.a[N-1][p] = '.';\n    } else { // 'D'\n        removed = b.a[N-1][p];\n        for (int i = N-1; i >= 1; i--) b.a[i][p] = b.a[i-1][p];\n        b.a[0][p] = '.';\n    }\n    return removed != 'o';\n}\n\nstatic bool verify_ops(const Board& init, const vector<pair<char,int>>& ops) {\n    if ((int)ops.size() > 4*N*N) return false;\n    Board b = init;\n    for (auto [d,p] : ops) {\n        if (!(0 <= p && p < N)) return false;\n        char rem;\n        if (!apply_move(b, d, p, rem)) return false; // removed 'o'\n    }\n    return count_x(b) == 0;\n}\n\n// Invariant: for every x, at least one of 4 directions to edge has no o\nstatic bool invariant_ok(const Board& b) {\n    int rowPref[N][N+1];\n    int colPref[N][N+1];\n    for (int i = 0; i < N; i++) {\n        rowPref[i][0] = 0;\n        for (int j = 0; j < N; j++) rowPref[i][j+1] = rowPref[i][j] + (b.a[i][j] == 'o');\n    }\n    for (int j = 0; j < N; j++) {\n        colPref[j][0] = 0;\n        for (int i = 0; i < N; i++) colPref[j][i+1] = colPref[j][i] + (b.a[i][j] == 'o');\n    }\n\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (b.a[i][j] == 'x') {\n        bool up    = (colPref[j][i] == 0);\n        bool down  = (colPref[j][N] - colPref[j][i+1] == 0);\n        bool left  = (rowPref[i][j] == 0);\n        bool right = (rowPref[i][N] - rowPref[i][j+1] == 0);\n        if (!(up || down || left || right)) return false;\n    }\n    return true;\n}\n\nstatic void compute_limits_from_board(const Board& b,\n                                      array<int,N>& left_limit,\n                                      array<int,N>& right_limit,\n                                      array<int,N>& up_limit,\n                                      array<int,N>& down_limit) {\n    for (int i = 0; i < N; i++) {\n        int first = N, last = -1;\n        for (int j = 0; j < N; j++) if (b.a[i][j] == 'o') { first = min(first, j); last = max(last, j); }\n        left_limit[i] = first;\n        right_limit[i] = (last == -1 ? N : (N-1-last));\n    }\n    for (int j = 0; j < N; j++) {\n        int first = N, last = -1;\n        for (int i = 0; i < N; i++) if (b.a[i][j] == 'o') { first = min(first, i); last = max(last, i); }\n        up_limit[j] = first;\n        down_limit[j] = (last == -1 ? N : (N-1-last));\n    }\n}\n\nstatic vector<pair<int,int>> extract_x_positions(const Board& b) {\n    vector<pair<int,int>> xs;\n    xs.reserve(40);\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (b.a[i][j] == 'x') xs.push_back({i,j});\n    return xs;\n}\n\nstruct OniOpt {\n    int r, c;\n    array<char,4> valid{};\n    array<int,4> group{};\n    array<int,4> depth{};\n    vector<int> feas;\n    bool fixed = false;\n};\n\nstatic vector<OniOpt> build_oni_options(const vector<pair<int,int>>& xs,\n                                       const array<int,N>& left_limit,\n                                       const array<int,N>& right_limit,\n                                       const array<int,N>& up_limit,\n                                       const array<int,N>& down_limit) {\n    vector<OniOpt> onis;\n    onis.reserve(xs.size());\n    for (auto [r,c] : xs) {\n        OniOpt o;\n        o.r = r; o.c = c;\n        // U\n        { int K = r+1; int g = gid(0,c);\n          if (K <= up_limit[c]) { o.valid[0]=1; o.group[0]=g; o.depth[0]=K; o.feas.push_back(0); } }\n        // D\n        { int K = N-r; int g = gid(1,c);\n          if (K <= down_limit[c]) { o.valid[1]=1; o.group[1]=g; o.depth[1]=K; o.feas.push_back(1); } }\n        // L\n        { int K = c+1; int g = gid(2,r);\n          if (K <= left_limit[r]) { o.valid[2]=1; o.group[2]=g; o.depth[2]=K; o.feas.push_back(2); } }\n        // R\n        { int K = N-c; int g = gid(3,r);\n          if (K <= right_limit[r]) { o.valid[3]=1; o.group[3]=g; o.depth[3]=K; o.feas.push_back(3); } }\n\n        if (o.feas.empty()) { // should not happen if invariant holds\n            o.valid[0]=1; o.group[0]=gid(0,c); o.depth[0]=1; o.feas.push_back(0);\n        }\n        o.fixed = (o.feas.size() == 1);\n        onis.push_back(o);\n    }\n    return onis;\n}\n\nstruct AssignState {\n    vector<int> dir;\n    array<array<uint8_t, MAXD+1>, G> cnt;\n    array<uint8_t, G> mx;\n    int cost = 0;\n};\n\nstatic void critical_prune(array<int,G>& mx, const vector<OniOpt>& onis) {\n    int M = (int)onis.size();\n    if (M == 0) { mx.fill(0); return; }\n\n    array<array<int, 64>, G> minReq;\n    for (int g = 0; g < G; g++) for (int i = 0; i < 64; i++) minReq[g][i] = INF;\n    for (int i = 0; i < M; i++) {\n        for (int d : onis[i].feas) {\n            int g = onis[i].group[d];\n            int need = onis[i].depth[d];\n            minReq[g][i] = min(minReq[g][i], need);\n        }\n    }\n\n    for (int it = 0; it < 60; it++) {\n        array<int,64> coverCnt{};\n        coverCnt.fill(0);\n        for (int g = 0; g < G; g++) if (mx[g] > 0) {\n            int dg = mx[g];\n            for (int i = 0; i < M; i++) if (minReq[g][i] <= dg) coverCnt[i]++;\n        }\n        bool changed = false;\n        for (int g = 0; g < G; g++) if (mx[g] > 0) {\n            int dg = mx[g];\n            int needMax = 0;\n            for (int i = 0; i < M; i++) {\n                if (minReq[g][i] <= dg && coverCnt[i] == 1) needMax = max(needMax, minReq[g][i]);\n            }\n            if (needMax < mx[g]) { mx[g] = needMax; changed = true; }\n        }\n        if (!changed) break;\n    }\n}\n\nstatic array<int,G> solve_assignment_SA(const vector<OniOpt>& onis, double timeBudgetSec, mt19937_64& rng) {\n    array<int,G> bestMx{};\n    bestMx.fill(0);\n    int M = (int)onis.size();\n    if (M == 0) return bestMx;\n\n    auto build_init = [&]() {\n        vector<int> dir(M, 0);\n        for (int i = 0; i < M; i++) {\n            int bestD = onis[i].feas[0];\n            int bestDep = onis[i].depth[bestD];\n            for (int d : onis[i].feas) {\n                int dep = onis[i].depth[d];\n                if (dep < bestDep) { bestDep = dep; bestD = d; }\n            }\n            dir[i] = bestD;\n        }\n        return dir;\n    };\n\n    auto build_state = [&](const vector<int>& dir) {\n        AssignState st;\n        st.dir = dir;\n        for (int g = 0; g < G; g++) {\n            st.mx[g] = 0;\n            for (int d = 0; d <= MAXD; d++) st.cnt[g][d] = 0;\n        }\n        st.cost = 0;\n        auto add = [&](int g, int d) {\n            st.cnt[g][d]++;\n            if (d > st.mx[g]) {\n                st.cost += (d - st.mx[g]);\n                st.mx[g] = (uint8_t)d;\n            }\n        };\n        for (int i = 0; i < M; i++) add(onis[i].group[dir[i]], onis[i].depth[dir[i]]);\n        return st;\n    };\n\n    auto remove_from = [&](AssignState& st, int g, int d) {\n        st.cnt[g][d]--;\n        if (d == st.mx[g] && st.cnt[g][d] == 0) {\n            int old = st.mx[g], nd = 0;\n            for (int x = old - 1; x >= 1; x--) if (st.cnt[g][x] > 0) { nd = x; break; }\n            st.mx[g] = (uint8_t)nd;\n            st.cost += (nd - old);\n        }\n    };\n    auto add_to = [&](AssignState& st, int g, int d) {\n        st.cnt[g][d]++;\n        if (d > st.mx[g]) {\n            st.cost += (d - st.mx[g]);\n            st.mx[g] = (uint8_t)d;\n        }\n    };\n    auto apply_change = [&](AssignState& st, int i, int nd) {\n        int od = st.dir[i];\n        if (od == nd) return 0;\n        int before = st.cost;\n        remove_from(st, onis[i].group[od], onis[i].depth[od]);\n        add_to(st, onis[i].group[nd], onis[i].depth[nd]);\n        st.dir[i] = nd;\n        return st.cost - before;\n    };\n\n    double stt = now_sec(), endt = stt + timeBudgetSec;\n    AssignState cur = build_state(build_init());\n    AssignState best = cur;\n\n    const double T0 = 25.0, T1 = 0.7;\n    long long iter = 0;\n\n    while (now_sec() < endt) {\n        double t = now_sec();\n        double p = (t - stt) / max(1e-9, timeBudgetSec);\n        p = min(1.0, max(0.0, p));\n        double temp = T0 * (1.0 - p) + T1 * p;\n\n        int i = rnd_int(rng, 0, M-1);\n        if (onis[i].fixed) continue;\n        const auto& f = onis[i].feas;\n        int od = cur.dir[i];\n        int nd = od;\n        for (int tries = 0; tries < 6; tries++) {\n            nd = f[rnd_int(rng, 0, (int)f.size()-1)];\n            if (nd != od) break;\n        }\n        if (nd == od) continue;\n\n        int delta = apply_change(cur, i, nd);\n        bool accept = (delta <= 0) || (rnd01(rng) < exp(-(double)delta / temp));\n        if (!accept) apply_change(cur, i, od);\n        else if (cur.cost < best.cost) best = cur;\n\n        if ((++iter & 4095) == 0) {\n            int j = rnd_int(rng, 0, M-1);\n            if (!onis[j].fixed) {\n                int od2 = cur.dir[j];\n                int bestd = od2, bestCost = cur.cost;\n                for (int cand : onis[j].feas) {\n                    if (cand == od2) continue;\n                    apply_change(cur, j, cand);\n                    if (cur.cost < bestCost) { bestCost = cur.cost; bestd = cand; }\n                    apply_change(cur, j, od2);\n                }\n                if (bestd != od2) apply_change(cur, j, bestd);\n                if (cur.cost < best.cost) best = cur;\n            }\n        }\n    }\n\n    for (int g = 0; g < G; g++) bestMx[g] = best.mx[g];\n    critical_prune(bestMx, onis);\n    return bestMx;\n}\n\nstatic vector<pair<char,int>> build_restore_ops(const array<int,G>& mx) {\n    vector<pair<char,int>> ops;\n    int sum = 0;\n    for (int g = 0; g < G; g++) sum += mx[g];\n    ops.reserve(4 * sum);\n\n    auto rep = [&](char d, int p, int k) { for (int i = 0; i < k; i++) ops.push_back({d,p}); };\n    for (int j = 0; j < N; j++) { int d = mx[gid(0,j)]; if (d) { rep('U', j, d); rep('D', j, d); } }\n    for (int j = 0; j < N; j++) { int d = mx[gid(1,j)]; if (d) { rep('D', j, d); rep('U', j, d); } }\n    for (int i = 0; i < N; i++) { int d = mx[gid(2,i)]; if (d) { rep('L', i, d); rep('R', i, d); } }\n    for (int i = 0; i < N; i++) { int d = mx[gid(3,i)]; if (d) { rep('R', i, d); rep('L', i, d); } }\n    return ops;\n}\n\n// Per-Oni restore fallback (requires invariant_ok)\nstatic vector<pair<char,int>> per_oni_restore(Board b) {\n    vector<pair<char,int>> ops;\n    ops.reserve(1600);\n\n    while (true) {\n        bool found = false;\n        int tr=-1, tc=-1;\n        for (int i = 0; i < N && !found; i++) for (int j = 0; j < N && !found; j++) if (b.a[i][j] == 'x') {\n            tr=i; tc=j; found=true;\n        }\n        if (!found) break;\n\n        int rowPref[N][N+1], colPref[N][N+1];\n        for (int i = 0; i < N; i++) {\n            rowPref[i][0]=0;\n            for (int j = 0; j < N; j++) rowPref[i][j+1]=rowPref[i][j]+(b.a[i][j]=='o');\n        }\n        for (int j = 0; j < N; j++) {\n            colPref[j][0]=0;\n            for (int i = 0; i < N; i++) colPref[j][i+1]=colPref[j][i]+(b.a[i][j]=='o');\n        }\n\n        struct Cand { int cost; char d; int p; int k; };\n        vector<Cand> cand;\n        if (colPref[tc][tr]==0) cand.push_back({2*(tr+1),'U',tc,tr+1});\n        if (colPref[tc][N]-colPref[tc][tr+1]==0) cand.push_back({2*(N-tr),'D',tc,N-tr});\n        if (rowPref[tr][tc]==0) cand.push_back({2*(tc+1),'L',tr,tc+1});\n        if (rowPref[tr][N]-rowPref[tr][tc+1]==0) cand.push_back({2*(N-tc),'R',tr,N-tc});\n        if (cand.empty()) break;\n\n        auto best = *min_element(cand.begin(), cand.end(), [](auto& a, auto& b){ return a.cost < b.cost; });\n\n        auto do_rep = [&](char d, int p, int k) {\n            for (int i = 0; i < k; i++) {\n                char rem;\n                (void)apply_move(b, d, p, rem);\n                ops.push_back({d,p});\n                if ((int)ops.size() > 1600) return;\n            }\n        };\n\n        if (best.d=='U') { do_rep('U',best.p,best.k); do_rep('D',best.p,best.k); }\n        else if (best.d=='D') { do_rep('D',best.p,best.k); do_rep('U',best.p,best.k); }\n        else if (best.d=='L') { do_rep('L',best.p,best.k); do_rep('R',best.p,best.k); }\n        else { do_rep('R',best.p,best.k); do_rep('L',best.p,best.k); }\n        if ((int)ops.size() > 1600) break;\n    }\n    return ops;\n}\n\n// Bulk clear efficient o-free lines (safe: can't remove 'o', and can't break invariant)\nstatic void bulk_clear_o_free_lines(Board& b, vector<pair<char,int>>& ops, int maxOps, double timeEnd) {\n    auto do_shift = [&](char d, int p, int k) {\n        for (int t = 0; t < k && (int)ops.size() < maxOps; t++) {\n            char rem;\n            (void)apply_move(b, d, p, rem);\n            ops.push_back({d,p});\n        }\n    };\n\n    while ((int)ops.size() < maxOps && now_sec() < timeEnd) {\n        int bestType=-1, bestIdx=-1, bestK=0, bestCnt=0;\n        char bestDir='?';\n        double bestEff = 0.0;\n\n        // rows\n        for (int r = 0; r < N; r++) {\n            bool hasO=false;\n            int cnt=0, mn=INF, mx=-1;\n            for (int j = 0; j < N; j++) {\n                char ch = b.a[r][j];\n                if (ch=='o') { hasO=true; break; }\n                if (ch=='x') { cnt++; mn=min(mn,j); mx=max(mx,j); }\n            }\n            if (hasO || cnt==0) continue;\n            int kL = mx+1, kR = N-mn;\n            int k = min(kL,kR);\n            char dir = (kL<=kR ? 'L' : 'R');\n\n            // Only do if \"efficient enough\" to avoid wasting moves\n            double eff = (double)cnt / (double)max(1,k);\n            bool good = (k<=2) || (cnt>=3 && eff>=0.45) || (cnt>=2 && eff>=0.60);\n            if (!good) continue;\n\n            if (eff > bestEff + 1e-12 || (abs(eff-bestEff)<=1e-12 && cnt>bestCnt)) {\n                bestEff=eff; bestType=0; bestIdx=r; bestK=k; bestDir=dir; bestCnt=cnt;\n            }\n        }\n        // cols\n        for (int c = 0; c < N; c++) {\n            bool hasO=false;\n            int cnt=0, mn=INF, mx=-1;\n            for (int i = 0; i < N; i++) {\n                char ch = b.a[i][c];\n                if (ch=='o') { hasO=true; break; }\n                if (ch=='x') { cnt++; mn=min(mn,i); mx=max(mx,i); }\n            }\n            if (hasO || cnt==0) continue;\n            int kU = mx+1, kD = N-mn;\n            int k = min(kU,kD);\n            char dir = (kU<=kD ? 'U' : 'D');\n\n            double eff = (double)cnt / (double)max(1,k);\n            bool good = (k<=2) || (cnt>=3 && eff>=0.45) || (cnt>=2 && eff>=0.60);\n            if (!good) continue;\n\n            if (eff > bestEff + 1e-12 || (abs(eff-bestEff)<=1e-12 && cnt>bestCnt)) {\n                bestEff=eff; bestType=1; bestIdx=c; bestK=k; bestDir=dir; bestCnt=cnt;\n            }\n        }\n\n        if (bestIdx < 0) break;\n        if ((int)ops.size() + bestK > maxOps) break;\n\n        do_shift(bestDir, bestIdx, bestK);\n        if (count_x(b) == 0) break;\n    }\n}\n\n// proven line_benefit from earlier good version\nstatic int line_benefit(const Board& bb, char d, int p) {\n    if (d == 'L' || d == 'R') {\n        int minc = INF, maxc = -1;\n        for (int j = 0; j < N; j++) if (bb.a[p][j] == 'x') { minc = min(minc, j); maxc = max(maxc, j); }\n        if (maxc < 0) return 0;\n        if (d == 'L') return 30 - minc;\n        else return 30 - (N-1-maxc);\n    } else {\n        int minr = INF, maxr = -1;\n        for (int i = 0; i < N; i++) if (bb.a[i][p] == 'x') { minr = min(minr, i); maxr = max(maxr, i); }\n        if (maxr < 0) return 0;\n        if (d == 'U') return 30 - minr;\n        else return 30 - (N-1-maxr);\n    }\n}\n\n// One attempt of invariant-preserving greedy + restore\nstatic vector<pair<char,int>> build_planB_once(const Board& init, mt19937_64& rng,\n                                              double greedyTime, double restoreTime,\n                                              bool stochasticPick) {\n    Board b = init;\n    vector<pair<char,int>> ops;\n    ops.reserve(1600);\n\n    if (!invariant_ok(b)) return {};\n\n    double st = now_sec();\n    double greedyEnd = st + greedyTime;\n\n    int maxGreedyMoves = 420;\n    int noProgress = 0;\n\n    while (now_sec() < greedyEnd && (int)ops.size() < maxGreedyMoves && count_x(b) > 0) {\n        // safe/cheap bulk clears\n        bulk_clear_o_free_lines(b, ops, maxGreedyMoves, greedyEnd);\n        if (count_x(b) == 0) break;\n        if ((int)ops.size() >= maxGreedyMoves) break;\n\n        struct Cand { int score; char d; int p; Board nb; };\n        array<Cand, 10> top; int topSz = 0;\n\n        int bestScore = -INF;\n        Cand bestC;\n\n        for (int p = 0; p < N; p++) for (char d : {'L','R','U','D'}) {\n            // boundary must not be o\n            char boundary;\n            if (d == 'L') boundary = b.a[p][0];\n            else if (d == 'R') boundary = b.a[p][N-1];\n            else if (d == 'U') boundary = b.a[0][p];\n            else boundary = b.a[N-1][p];\n            if (boundary == 'o') continue;\n\n            Board tmp = b;\n            char rem;\n            if (!apply_move(tmp, d, p, rem)) continue;\n            if (!invariant_ok(tmp)) continue;\n\n            int removedX = (rem == 'x') ? 1 : 0;\n\n            // penalty: if repeating same move becomes impossible immediately (o at new boundary)\n            char newBoundary;\n            if (d == 'L') newBoundary = tmp.a[p][0];\n            else if (d == 'R') newBoundary = tmp.a[p][N-1];\n            else if (d == 'U') newBoundary = tmp.a[0][p];\n            else newBoundary = tmp.a[N-1][p];\n            int blockPenalty = (newBoundary == 'o') ? 40 : 0;\n\n            int score = removedX * 10000 + line_benefit(b, d, p) - 1 - blockPenalty;\n            score += rnd_int(rng, 0, 2);\n\n            Cand c{score, d, p, tmp};\n\n            // track best\n            if (score > bestScore) { bestScore = score; bestC = c; }\n\n            // keep small top list\n            if (topSz < (int)top.size()) top[topSz++] = c;\n            else {\n                int mi = 0;\n                for (int i = 1; i < topSz; i++) if (top[i].score < top[mi].score) mi = i;\n                if (score > top[mi].score) top[mi] = c;\n            }\n        }\n\n        if (bestScore <= 0) break;\n\n        Cand chosen = bestC;\n        if (stochasticPick && topSz > 0 && rnd01(rng) < 0.18) {\n            // choose among best 3 in top-list\n            vector<int> idx(topSz);\n            iota(idx.begin(), idx.end(), 0);\n            sort(idx.begin(), idx.end(), [&](int a, int b){ return top[a].score > top[b].score; });\n            int K = min(3, topSz);\n            chosen = top[idx[rnd_int(rng, 0, K-1)]];\n            bestScore = chosen.score;\n        }\n\n        b = chosen.nb;\n        ops.push_back({chosen.d, chosen.p});\n\n        if (bestScore >= 10000) noProgress = 0;\n        else noProgress++;\n        if (noProgress > 65) break;\n    }\n\n    // final bulk clears with remaining time (still safe)\n    bulk_clear_o_free_lines(b, ops, 1600, st + greedyTime);\n\n    // Restore phase\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    compute_limits_from_board(b, left_limit, right_limit, up_limit, down_limit);\n\n    auto xs = extract_x_positions(b);\n    auto onis = build_oni_options(xs, left_limit, right_limit, up_limit, down_limit);\n\n    auto mx = solve_assignment_SA(onis, restoreTime, rng);\n    auto restore = build_restore_ops(mx);\n\n    // quick verify on current b\n    {\n        Board tmp = b;\n        bool ok = true;\n        for (auto [d,p] : restore) {\n            char rem;\n            if (!apply_move(tmp, d, p, rem)) { ok = false; break; }\n        }\n        if (ok && count_x(tmp) == 0 && (int)ops.size() + (int)restore.size() <= 1600) {\n            ops.insert(ops.end(), restore.begin(), restore.end());\n            if (verify_ops(init, ops)) return ops;\n        }\n    }\n\n    // fallback: per-oni restore (guaranteed if invariant holds)\n    if (!invariant_ok(b)) return {};\n    auto fb = per_oni_restore(b);\n    if ((int)ops.size() + (int)fb.size() <= 1600) {\n        ops.insert(ops.end(), fb.begin(), fb.end());\n        if (verify_ops(init, ops)) return ops;\n    }\n\n    return {};\n}\n\nstatic vector<pair<char,int>> restore_only(const Board& init, mt19937_64& rng, double saTime) {\n    array<int,N> left_limit, right_limit, up_limit, down_limit;\n    compute_limits_from_board(init, left_limit, right_limit, up_limit, down_limit);\n    auto xs = extract_x_positions(init);\n    auto onis = build_oni_options(xs, left_limit, right_limit, up_limit, down_limit);\n    auto mx = solve_assignment_SA(onis, saTime, rng);\n    auto ops = build_restore_ops(mx);\n    if (verify_ops(init, ops)) return ops;\n    // statement guarantees solvable\n    return per_oni_restore(init);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    vector<string> C(n);\n    for (int i = 0; i < n; i++) cin >> C[i];\n\n    Board init = read_board(C);\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937_64 rng(seed);\n\n    double globalStart = now_sec();\n    const double TOTAL = 1.95;\n\n    vector<pair<char,int>> best;\n    int bestLen = INF;\n\n    // Attempt 0: restore-only baseline (small)\n    {\n        auto ops = restore_only(init, rng, 0.20);\n        if (!ops.empty() && (int)ops.size() < bestLen) { bestLen = (int)ops.size(); best = std::move(ops); }\n    }\n\n    // Greedy attempts (mostly like the proven strong approach), with a bit more diversification\n    int attempts = 4;\n    for (int a = 0; a < attempts; a++) {\n        double elapsed = now_sec() - globalStart;\n        double remain = TOTAL - elapsed;\n        if (remain < 0.22) break;\n\n        double slice = remain / (attempts - a);\n        double greedyTime  = min(0.75, max(0.30, slice * 0.70));\n        double restoreTime = min(0.35, max(0.10, slice * 0.27));\n\n        bool stochastic = (a != 0); // first greedy attempt deterministic\n        auto ops = build_planB_once(init, rng, greedyTime, restoreTime, stochastic);\n        if (!ops.empty() && (int)ops.size() < bestLen) { bestLen = (int)ops.size(); best = std::move(ops); }\n    }\n\n    if (best.empty() || !verify_ops(init, best)) {\n        // absolute safety fallback (should never happen)\n        best = per_oni_restore(init);\n    }\n\n    if ((int)best.size() > 1600) best.clear();\n    for (auto [d,p] : best) cout << d << \" \" << p << \"\\n\";\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 100;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int mod) { return (int)(nextU64() % (uint64_t)mod); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline int iabs_int(int x) { return x < 0 ? -x : x; }\nstatic inline long long iabs_ll(long long x) { return x < 0 ? -x : x; }\n\nstruct Plan {\n    array<int, N> a;\n    array<int, N> b;\n};\n\nint simulate_plan(const Plan& p, int L, const array<int, N>& T, array<int, N>& cnt) {\n    cnt.fill(0);\n    int cur = 0;\n    cnt[0] = 1;\n    for (int step = 1; step < L; ++step) {\n        int x = cur;\n        cur = (cnt[x] & 1) ? p.a[x] : p.b[x];\n        ++cnt[cur];\n    }\n    int E = 0;\n    for (int i = 0; i < N; ++i) E += iabs_int(cnt[i] - T[i]);\n    return E;\n}\n\n// Kosaraju SCC on \"core nodes\", edges are a[v], b[v] (assumed to be within core for v in core)\nint scc_core(const Plan& p, const vector<int>& core, const array<char, N>& inCore,\n             array<int, N>& compOut) {\n    vector<int> nodes = core;\n    int K = (int)nodes.size();\n    if (K == 0) return 0;\n    // map node -> idx not needed; use inCore check\n    vector<vector<int>> rg(N); rg.assign(N, {});\n    vector<vector<int>> g(N);  g.assign(N, {});\n    for (int v : nodes) {\n        int to1 = p.a[v], to2 = p.b[v];\n        g[v].push_back(to1);\n        g[v].push_back(to2);\n        rg[to1].push_back(v);\n        rg[to2].push_back(v);\n    }\n    vector<char> vis(N, 0);\n    vector<int> order; order.reserve(K);\n\n    auto dfs1 = [&](auto&& self, int v) -> void {\n        vis[v] = 1;\n        for (int to : g[v]) if (inCore[to] && !vis[to]) self(self, to);\n        order.push_back(v);\n    };\n    for (int v : nodes) if (!vis[v]) dfs1(dfs1, v);\n\n    compOut.fill(-1);\n    int compCnt = 0;\n    auto dfs2 = [&](auto&& self, int v) -> void {\n        compOut[v] = compCnt;\n        for (int to : rg[v]) if (inCore[to] && compOut[to] == -1) self(self, to);\n    };\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (compOut[v] == -1) {\n            dfs2(dfs2, v);\n            ++compCnt;\n        }\n    }\n    return compCnt;\n}\n\n// Static balance objective on core:\n// incomingW[j] = sum_{i in core} T[i] * [a_i==j] + T[i] * [b_i==j]\n// want incomingW[j] ~= 2*T[j]\nstruct StaticBalance {\n    array<long long, N> D; // D[j] = incomingW[j] - 2*T[j], only meaningful on core\n    long long F = 0;       // sum |D[j]| over core\n};\n\nStaticBalance compute_static_balance(const Plan& p, const array<int, N>& T,\n                                     const vector<int>& core, const array<char, N>& inCore) {\n    array<long long, N> incoming{};\n    incoming.fill(0);\n    for (int i : core) {\n        incoming[p.a[i]] += T[i];\n        incoming[p.b[i]] += T[i];\n    }\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = incoming[j] - 2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n    return sb;\n}\n\ninline long long delta_move_edge(long long Dold, long long Dnew, int w) {\n    // Move one edge of weight w: D_old -= w, D_new += w\n    long long before = iabs_ll(Dold) + iabs_ll(Dnew);\n    long long after  = iabs_ll(Dold - w) + iabs_ll(Dnew + w);\n    return after - before;\n}\n\ninline void apply_move_edge(StaticBalance& sb, int oldDest, int newDest, int w) {\n    // assumes oldDest,newDest are in core and w>=0\n    sb.F -= iabs_ll(sb.D[oldDest]);\n    sb.D[oldDest] -= w;\n    sb.F += iabs_ll(sb.D[oldDest]);\n\n    sb.F -= iabs_ll(sb.D[newDest]);\n    sb.D[newDest] += w;\n    sb.F += iabs_ll(sb.D[newDest]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, L;\n    cin >> Nin >> L;\n    array<int, N> T{};\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    uint64_t seed = 123456789ULL;\n    for (int i = 0; i < N; ++i) seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    RNG rng(seed);\n\n    auto time_start = chrono::steady_clock::now();\n    auto elapsedSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - time_start).count();\n    };\n    const double TIME_LIMIT = 1.95;\n\n    // Core: nodes with positive target\n    array<char, N> inCore{};\n    inCore.fill(0);\n    vector<int> core;\n    core.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        if (T[i] > 0) { inCore[i] = 1; core.push_back(i); }\n    }\n\n    // Edge case: if somehow core is empty (shouldn't happen since sum T = L), make core {0}\n    if (core.empty()) { inCore[0] = 1; core.push_back(0); }\n\n    int hub = core[0];\n    for (int v : core) if (T[v] > T[hub]) hub = v;\n\n    Plan p;\n    p.a.fill(hub);\n    p.b.fill(hub);\n\n    // ----- Initial construction: greedy best-improvement per edge on static objective -----\n    // Initialize D = -2*T on core\n    StaticBalance sb;\n    sb.D.fill(0);\n    sb.F = 0;\n    for (int j : core) {\n        sb.D[j] = -2LL * T[j];\n        sb.F += iabs_ll(sb.D[j]);\n    }\n\n    // Assign edges for core nodes to reduce F\n    for (int i : core) {\n        int w = T[i];\n        for (int e = 0; e < 2; ++e) {\n            int bestJ = core[rng.nextInt((int)core.size())];\n            long long bestDelta = (1LL<<62);\n\n            // If weight is 0 (shouldn't inside core), just random to help connectivity later\n            if (w == 0) {\n                bestJ = core[rng.nextInt((int)core.size())];\n                bestDelta = 0;\n            } else {\n                for (int j : core) {\n                    // currently edge points to hub, but we are building from scratch: treat as adding w to j\n                    long long before = iabs_ll(sb.D[j]);\n                    long long after  = iabs_ll(sb.D[j] + w);\n                    long long delta = after - before;\n                    if (delta < bestDelta || (delta == bestDelta && rng.nextInt(8) == 0)) {\n                        bestDelta = delta;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            // Apply: oldDest was \"none\" (incoming 0), but our sb.D already includes only demand.\n            // So just D[bestJ] += w, update F accordingly.\n            sb.F -= iabs_ll(sb.D[bestJ]);\n            sb.D[bestJ] += w;\n            sb.F += iabs_ll(sb.D[bestJ]);\n\n            if (e == 0) p.a[i] = bestJ;\n            else p.b[i] = bestJ;\n        }\n    }\n\n    // Non-core nodes: point to hub (won't be visited if core is closed and 0 in core; if 0 not in core, it is transient)\n    for (int i = 0; i < N; ++i) if (!inCore[i]) {\n        p.a[i] = hub;\n        p.b[i] = hub;\n    }\n\n    // If 0 is not in core, ensure it enters core immediately and never referenced by core (we keep core closed)\n    if (!inCore[0]) {\n        p.a[0] = hub;\n        p.b[0] = hub;\n    }\n\n    // Recompute sb properly from plan (for correctness after our incremental build)\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Fast SA on static balance objective -----\n    // Periodically keep sorted lists of deficits\n    vector<int> core_sorted = core;\n\n    auto resort_core = [&]() {\n        core_sorted = core;\n        sort(core_sorted.begin(), core_sorted.end(), [&](int x, int y) {\n            return sb.D[x] < sb.D[y]; // more negative first (needs incoming)\n        });\n    };\n    resort_core();\n\n    // Weighted source selection among core based on T[i]\n    vector<long long> pref;\n    pref.reserve(core.size()+1);\n    auto build_pref = [&]() {\n        pref.assign(core.size()+1, 0);\n        for (int k = 0; k < (int)core.size(); ++k) {\n            pref[k+1] = pref[k] + max(1, T[core[k]]); // avoid all-zero\n        }\n    };\n    build_pref();\n\n    auto pick_core_weighted = [&]() -> int {\n        long long sum = pref.back();\n        long long r = (long long)(rng.nextU64() % (uint64_t)sum);\n        int k = (int)(upper_bound(pref.begin(), pref.end(), r) - pref.begin()) - 1;\n        if (k < 0) k = 0;\n        if (k >= (int)core.size()) k = (int)core.size()-1;\n        return core[k];\n    };\n\n    const double STATIC_END = 0.65; // seconds budget for static stage\n    long long bestF = sb.F;\n    Plan bestStatic = p;\n\n    int iter = 0;\n    while (elapsedSec() < STATIC_END && !core.empty()) {\n        ++iter;\n        if ((iter & 1023) == 0) resort_core();\n\n        int i = (rng.nextInt(100) < 75) ? pick_core_weighted() : core[rng.nextInt((int)core.size())];\n        int w = T[i];\n        int e = rng.nextInt(2);\n        int& edge = (e == 0 ? p.a[i] : p.b[i]);\n        int oldDest = edge;\n\n        // choose new destination among a small candidate set\n        int candCount = 10;\n        long long bestDelta = (1LL<<62);\n        int bestDest = oldDest;\n\n        for (int t = 0; t < candCount; ++t) {\n            int newDest;\n            if (rng.nextInt(100) < 75) {\n                // pick from most-negative (needs incoming)\n                int idx = rng.nextInt(min(20, (int)core_sorted.size()));\n                newDest = core_sorted[idx];\n            } else {\n                newDest = core[rng.nextInt((int)core.size())];\n            }\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d < bestDelta) { bestDelta = d; bestDest = newDest; }\n        }\n        if (bestDest == oldDest) continue;\n\n        // SA acceptance on static objective\n        double tcur = min(1.0, elapsedSec() / STATIC_END);\n        double temp = 2000.0 * pow(1.0 / 2000.0, tcur); // 2000 -> 1\n        bool accept = false;\n        if (bestDelta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)bestDelta / temp)) accept = true;\n\n        if (!accept) continue;\n\n        // apply\n        apply_move_edge(sb, oldDest, bestDest, w);\n        edge = bestDest;\n\n        if (sb.F < bestF) {\n            bestF = sb.F;\n            bestStatic = p;\n        }\n    }\n    p = bestStatic;\n    sb = compute_static_balance(p, T, core, inCore);\n\n    // ----- Repair: make core strongly connected (to avoid falling into a sink SCC subset) -----\n    array<int, N> comp{};\n    int compCnt = scc_core(p, core, inCore, comp);\n    int repairRounds = 0;\n    while (compCnt > 1 && elapsedSec() < 0.90 && repairRounds < 50) {\n        ++repairRounds;\n\n        vector<int> rep(compCnt, -1);\n        for (int v : core) {\n            int c = comp[v];\n            if (rep[c] == -1 || T[v] < T[rep[c]]) rep[c] = v;\n        }\n        // connect components in a cycle using minimal-static-delta edge rewires\n        for (int c = 0; c < compCnt; ++c) {\n            int from = rep[c];\n            int to = rep[(c+1) % compCnt];\n            if (from == -1 || to == -1) continue;\n            if (p.a[from] == to || p.b[from] == to) continue;\n\n            int w = T[from];\n\n            // choose whether to replace a or b to minimize static damage\n            long long da = delta_move_edge(sb.D[p.a[from]], sb.D[to], w);\n            long long db = delta_move_edge(sb.D[p.b[from]], sb.D[to], w);\n\n            if (da <= db) {\n                int old = p.a[from];\n                apply_move_edge(sb, old, to, w);\n                p.a[from] = to;\n            } else {\n                int old = p.b[from];\n                apply_move_edge(sb, old, to, w);\n                p.b[from] = to;\n            }\n        }\n\n        // small local clean-up on static objective after rewiring\n        for (int k = 0; k < 2000; ++k) {\n            int i = pick_core_weighted();\n            int w = T[i];\n            int e = rng.nextInt(2);\n            int& edge = (e == 0 ? p.a[i] : p.b[i]);\n            int oldDest = edge;\n\n            int newDest = core[rng.nextInt((int)core.size())];\n            if (newDest == oldDest) continue;\n            long long d = delta_move_edge(sb.D[oldDest], sb.D[newDest], w);\n            if (d <= 0) {\n                apply_move_edge(sb, oldDest, newDest, w);\n                edge = newDest;\n            }\n        }\n\n        compCnt = scc_core(p, core, inCore, comp);\n    }\n\n    // ----- Exact simulation SA on real objective -----\n    array<int, N> curCnt{}, bestCnt{}, tmpCnt{};\n    Plan curP = p, bestP = p;\n    int curE = simulate_plan(curP, L, T, curCnt);\n    int bestE = curE;\n    bestCnt = curCnt;\n\n    auto pick_x = [&]() -> int {\n        // choose among core (if 0 not in core, it is only visited once; no need to optimize edges by counts)\n        if (core.size() == 1) return core[0];\n        // rejection sampling biased by visit counts\n        int maxC = 1;\n        for (int v : core) maxC = max(maxC, curCnt[v]);\n        while (true) {\n            int v = core[rng.nextInt((int)core.size())];\n            if (rng.nextInt(maxC) < curCnt[v]) return v;\n        }\n    };\n\n    auto pick_dest_deficit = [&]() -> int {\n        // pick a destination in core biased to under-visited nodes\n        int maxD = 1;\n        for (int v : core) maxD = max(maxD, max(0, T[v] - curCnt[v]));\n        for (int tries = 0; tries < 50; ++tries) {\n            int v = core[rng.nextInt((int)core.size())];\n            int d = max(0, T[v] - curCnt[v]);\n            if (rng.nextInt(maxD) < d + 1) return v;\n        }\n        return core[rng.nextInt((int)core.size())];\n    };\n\n    auto core_strong_connected = [&](const Plan& pp) -> bool {\n        if (core.size() <= 1) return true;\n        // BFS from some start in core\n        int s = core[0];\n        vector<char> vis(N, 0);\n        deque<int> dq;\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            int to1 = pp.a[v], to2 = pp.b[v];\n            if (inCore[to1] && !vis[to1]) { vis[to1] = 1; dq.push_back(to1); }\n            if (inCore[to2] && !vis[to2]) { vis[to2] = 1; dq.push_back(to2); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n\n        // reverse BFS\n        vector<vector<int>> rg(N);\n        for (int v : core) {\n            rg[pp.a[v]].push_back(v);\n            rg[pp.b[v]].push_back(v);\n        }\n        fill(vis.begin(), vis.end(), 0);\n        vis[s] = 1; dq.push_back(s);\n        while (!dq.empty()) {\n            int v = dq.front(); dq.pop_front();\n            for (int u : rg[v]) if (inCore[u] && !vis[u]) { vis[u] = 1; dq.push_back(u); }\n        }\n        for (int v : core) if (!vis[v]) return false;\n        return true;\n    };\n\n    const double DYN_START = elapsedSec();\n    while (elapsedSec() < TIME_LIMIT) {\n        double t = (elapsedSec() - DYN_START) / max(1e-9, (TIME_LIMIT - DYN_START));\n        t = min(1.0, max(0.0, t));\n        double temp = 6000.0 * pow(30.0 / 6000.0, t);\n\n        int type = rng.nextInt(100);\n        int x1=-1, e1=0, old1=-1;\n        int x2=-1, e2=0, old2=-1;\n        int olda=-1, oldb=-1;\n\n        if (type < 72) {\n            // change one edge\n            x1 = pick_x();\n            e1 = rng.nextInt(2);\n            int& edge = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            old1 = edge;\n            int y = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y == old1) continue;\n            edge = y;\n        } else if (type < 92) {\n            // swap two edges\n            x1 = pick_x(); e1 = rng.nextInt(2);\n            x2 = pick_x(); e2 = rng.nextInt(2);\n            int& ed1 = (e1==0 ? curP.a[x1] : curP.b[x1]);\n            int& ed2 = (e2==0 ? curP.a[x2] : curP.b[x2]);\n            old1 = ed1; old2 = ed2;\n            if (old1 == old2) continue;\n            ed1 = old2; ed2 = old1;\n        } else {\n            // reset both edges of one node\n            x1 = pick_x();\n            olda = curP.a[x1];\n            oldb = curP.b[x1];\n            int y1 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            int y2 = (rng.nextInt(100) < 80) ? pick_dest_deficit() : core[rng.nextInt((int)core.size())];\n            if (y1 == olda && y2 == oldb) continue;\n            curP.a[x1] = y1;\n            curP.b[x1] = y2;\n        }\n\n        // Keep core closed (should already hold by how we pick destinations), and keep core strongly connected\n        if (!core_strong_connected(curP)) {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n            continue;\n        }\n\n        int newE = simulate_plan(curP, L, T, tmpCnt);\n        int delta = newE - curE;\n\n        bool accept = false;\n        if (delta <= 0) accept = true;\n        else if (rng.nextDouble() < exp(-(double)delta / temp)) accept = true;\n\n        if (accept) {\n            curE = newE;\n            curCnt = tmpCnt;\n            if (curE < bestE) {\n                bestE = curE;\n                bestP = curP;\n                bestCnt = curCnt;\n            }\n        } else {\n            // revert\n            if (type < 72) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n            } else if (type < 92) {\n                if (e1==0) curP.a[x1] = old1; else curP.b[x1] = old1;\n                if (e2==0) curP.a[x2] = old2; else curP.b[x2] = old2;\n            } else {\n                curP.a[x1] = olda;\n                curP.b[x1] = oldb;\n            }\n        }\n    }\n\n    // Output best plan found\n    for (int i = 0; i < N; ++i) {\n        cout << bestP.a[i] << ' ' << bestP.b[i] << \"\\n\";\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\n#include <atcoder/dsu>\nusing namespace std;\n\nstruct City {\n    int lx, rx, ly, ry;\n    int cx, cy;\n    uint32_t morton;\n};\n\nstatic inline uint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nstatic inline uint32_t morton2D(uint32_t x, uint32_t y) {\n    return part1by1(x) | (part1by1(y) << 1);\n}\n\nstruct EdgeW { int a, b; uint16_t w; };\n\nstruct CandEdge {\n    int a, b;\n    uint16_t lb;\n    uint16_t cd;\n    uint8_t tp; // 0=query,1=neighbor,2=fallback\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    int ms() const {\n        return (int)chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Solver {\n    static constexpr int TIME_GUARD_MS = 1650;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<City> cities;\n\n    vector<uint16_t> centerMat; // N*N\n    vector<uint16_t> lbMat;     // N*N\n\n    Timer timer;\n    int q_used = 0;\n\n    vector<vector<int>> groups;\n    vector<vector<pair<int,int>>> queryEdges;\n    vector<char> fullQueried;\n\n    vector<vector<pair<int,int>>> fallbackEdges;\n    vector<vector<EdgeW>> fallbackEdgesW;\n    vector<long long> groupEstCost;\n    vector<int> groupMaxEdge;\n\n    // reusable Prim buffers\n    vector<uint16_t> prim_minc;\n    vector<int> prim_parent;\n    vector<char> prim_used;\n\n    inline bool time_ok() const { return timer.ms() <= TIME_GUARD_MS; }\n    inline uint16_t cdist(int a, int b) const { return centerMat[a * N + b]; }\n    inline uint16_t lbdist(int a, int b) const { return lbMat[a * N + b]; }\n\n    static inline int isqrt_floor_ll(long long v) {\n        if (v <= 0) return 0;\n        long long r = (long long)floor(sqrt((long double)v));\n        while ((r + 1) * (r + 1) <= v) ++r;\n        while (r * r > v) --r;\n        return (int)r;\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        int l = (int)subset.size();\n        cout << \"? \" << l;\n        for (int v : subset) cout << \" \" << v;\n        cout << \"\\n\" << flush;\n\n        vector<pair<int,int>> edges;\n        edges.reserve(max(0, l - 1));\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            cin >> a >> b;\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        q_used++;\n        return edges;\n    }\n\n    long long prim_sum(const vector<int>& nodes, const uint16_t* mat) {\n        int s = (int)nodes.size();\n        if (s <= 1) return 0;\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n\n        if ((int)prim_minc.size() < s) {\n            prim_minc.resize(s);\n            prim_parent.resize(s);\n            prim_used.resize(s);\n        }\n        for (int i = 0; i < s; i++) {\n            prim_minc[i] = INF;\n            prim_parent[i] = -1;\n            prim_used[i] = 0;\n        }\n        prim_minc[0] = 0;\n\n        long long sum = 0;\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) if (!prim_used[i]) {\n                if (v == -1 || prim_minc[i] < prim_minc[v]) v = i;\n            }\n            prim_used[v] = 1;\n            if (prim_parent[v] != -1) sum += prim_minc[v];\n\n            int va = nodes[v];\n            const uint16_t* row = mat + va * N;\n            for (int u = 0; u < s; u++) if (!prim_used[u]) {\n                uint16_t d = row[nodes[u]];\n                if (d < prim_minc[u]) {\n                    prim_minc[u] = d;\n                    prim_parent[u] = v;\n                }\n            }\n        }\n        return sum;\n    }\n\n    long long prim_build_center_edges(const vector<int>& nodes, vector<pair<int,int>>& outEdges, vector<EdgeW>& outEdgesW) {\n        int s = (int)nodes.size();\n        outEdges.clear();\n        outEdgesW.clear();\n        if (s <= 1) return 0;\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n\n        if ((int)prim_minc.size() < s) {\n            prim_minc.resize(s);\n            prim_parent.resize(s);\n            prim_used.resize(s);\n        }\n        for (int i = 0; i < s; i++) {\n            prim_minc[i] = INF;\n            prim_parent[i] = -1;\n            prim_used[i] = 0;\n        }\n        prim_minc[0] = 0;\n\n        long long sum = 0;\n        for (int it = 0; it < s; it++) {\n            int v = -1;\n            for (int i = 0; i < s; i++) if (!prim_used[i]) {\n                if (v == -1 || prim_minc[i] < prim_minc[v]) v = i;\n            }\n            prim_used[v] = 1;\n\n            if (prim_parent[v] != -1) {\n                int a = nodes[v], b = nodes[prim_parent[v]];\n                uint16_t w = cdist(a, b);\n                sum += (int)w;\n                if (a > b) swap(a, b);\n                outEdges.push_back({a, b});\n                outEdgesW.push_back({a, b, w});\n            }\n\n            int va = nodes[v];\n            const uint16_t* row = centerMat.data() + va * N;\n            for (int u = 0; u < s; u++) if (!prim_used[u]) {\n                uint16_t d = row[nodes[u]];\n                if (d < prim_minc[u]) {\n                    prim_minc[u] = d;\n                    prim_parent[u] = v;\n                }\n            }\n        }\n        return sum;\n    }\n\n    vector<vector<int>> build_groups_sweep(const vector<int>& order, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        int idx = 0;\n        for (int t = 0; t < M; t++) {\n            int k = groupOrder[t];\n            gr[k].reserve(G[k]);\n            for (int i = 0; i < G[k]; i++) gr[k].push_back(order[idx++]);\n        }\n        return gr;\n    }\n\n    vector<vector<int>> build_groups_grow(const vector<int>& seedOrder, const vector<int>& groupOrder) {\n        vector<vector<int>> gr(M);\n        vector<char> used(N, false);\n        vector<uint16_t> best(N);\n        int ptr = 0;\n\n        auto next_seed = [&]() -> int {\n            while (ptr < N && used[seedOrder[ptr]]) ptr++;\n            if (ptr >= N) {\n                for (int i = 0; i < N; i++) if (!used[i]) return i;\n                return -1;\n            }\n            return seedOrder[ptr];\n        };\n\n        const uint16_t INF = numeric_limits<uint16_t>::max();\n        for (int gid : groupOrder) {\n            int need = G[gid];\n            gr[gid].clear();\n            gr[gid].reserve(need);\n\n            int seed = next_seed();\n            if (seed < 0) break;\n            used[seed] = true;\n            gr[gid].push_back(seed);\n\n            for (int v = 0; v < N; v++) best[v] = used[v] ? INF : cdist(seed, v);\n\n            for (int t = 1; t < need; t++) {\n                int pick = -1;\n                uint16_t bd = INF;\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = best[v];\n                    if (pick == -1 || d < bd) { bd = d; pick = v; }\n                }\n                if (pick < 0) break;\n                used[pick] = true;\n                gr[gid].push_back(pick);\n\n                const uint16_t* row = centerMat.data() + pick * N;\n                for (int v = 0; v < N; v++) if (!used[v]) {\n                    uint16_t d = row[v];\n                    if (d < best[v]) best[v] = d;\n                }\n            }\n        }\n        return gr;\n    }\n\n    // LB-aware subset selection around edge (u,v)\n    vector<int> make_edge_subset(int k, int u, int v) {\n        const auto &nodes = groups[k];\n        int s = (int)nodes.size();\n        int want = min(L, s);\n        if (want < 3) return {u, v};\n\n        int rem = want - 2;\n        int a_take = rem / 2;\n        int b_take = rem - a_take;\n\n        struct KeyV { uint16_t lb, cd; int x; };\n        auto cmpKey = [](const KeyV& A, const KeyV& B){\n            if (A.lb != B.lb) return A.lb < B.lb;\n            if (A.cd != B.cd) return A.cd < B.cd;\n            return A.x < B.x;\n        };\n\n        vector<KeyV> cu, cv;\n        cu.reserve(s);\n        cv.reserve(s);\n        for (int x : nodes) {\n            if (x == u || x == v) continue;\n            cu.push_back({lbdist(u, x), cdist(u, x), x});\n            cv.push_back({lbdist(v, x), cdist(v, x), x});\n        }\n\n        auto take_best = [&](vector<KeyV>& c, int take) {\n            if (take <= 0) { c.clear(); return; }\n            if ((int)c.size() > take) {\n                nth_element(c.begin(), c.begin() + take, c.end(),\n                            [&](auto &A, auto &B){ return cmpKey(A,B); });\n                c.resize(take);\n            }\n            sort(c.begin(), c.end(), [&](auto &A, auto &B){ return cmpKey(A,B); });\n        };\n        take_best(cu, a_take);\n        take_best(cv, b_take);\n\n        vector<int> subset;\n        subset.reserve(want);\n        subset.push_back(u);\n        subset.push_back(v);\n\n        auto push_unique = [&](int x) {\n            for (int y : subset) if (y == x) return;\n            subset.push_back(x);\n        };\n        for (auto &p : cu) push_unique(p.x);\n        for (auto &p : cv) push_unique(p.x);\n\n        if ((int)subset.size() < want) {\n            vector<KeyV> fill;\n            fill.reserve(s);\n            for (int x : nodes) {\n                bool ok = true;\n                for (int y : subset) if (y == x) { ok = false; break; }\n                if (!ok) continue;\n                uint16_t lb = min(lbdist(u,x), lbdist(v,x));\n                uint16_t cd = min(cdist(u,x), cdist(v,x));\n                fill.push_back({lb, cd, x});\n            }\n            int need = want - (int)subset.size();\n            if ((int)fill.size() > need) {\n                nth_element(fill.begin(), fill.begin() + need, fill.end(),\n                            [&](auto &A, auto &B){ return cmpKey(A,B); });\n                fill.resize(need);\n            }\n            sort(fill.begin(), fill.end(), [&](auto &A, auto &B){ return cmpKey(A,B); });\n            for (auto &p : fill) subset.push_back(p.x);\n        }\n\n        if ((int)subset.size() > want) subset.resize(want);\n        return subset;\n    }\n\n    static uint64_t subset_hash(vector<int> sub) {\n        sort(sub.begin(), sub.end());\n        uint64_t x = 1469598103934665603ULL;\n        for (int v : sub) { x ^= (uint64_t)(v + 1); x *= 1099511628211ULL; }\n        return x;\n    }\n\n    vector<pair<int,int>> build_neighbor_edges(const vector<int>& nodes, int Kwin) {\n        int s = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (s <= 1) return edges;\n        edges.reserve((size_t)s * Kwin * 3);\n\n        auto add_window = [&](vector<int>& ord) {\n            for (int i = 0; i < s; i++) {\n                int u = ord[i];\n                for (int d = 1; d <= Kwin && i + d < s; d++) {\n                    int v = ord[i + d];\n                    int a = u, b = v;\n                    if (a > b) swap(a, b);\n                    edges.emplace_back(a, b);\n                }\n            }\n        };\n\n        vector<int> ordx = nodes, ordy = nodes, ordm = nodes;\n        sort(ordx.begin(), ordx.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return a < b;\n        });\n        sort(ordy.begin(), ordy.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return a < b;\n        });\n        sort(ordm.begin(), ordm.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return a < b;\n        });\n\n        add_window(ordx);\n        add_window(ordy);\n        add_window(ordm);\n\n        sort(edges.begin(), edges.end());\n        edges.erase(unique(edges.begin(), edges.end()), edges.end());\n        return edges;\n    }\n\n    vector<pair<int,int>> build_final_tree(int k) {\n        const vector<int>& nodes = groups[k];\n        int s = (int)nodes.size();\n        if (s <= 1) return {};\n        if (s == 2) {\n            int a = nodes[0], b = nodes[1];\n            if (a > b) swap(a,b);\n            return {{a,b}};\n        }\n\n        if (fullQueried[k]) {\n            auto res = queryEdges[k];\n            if ((int)res.size() == s - 1) return res;\n        }\n\n        vector<int> pos(N, -1);\n        for (int i = 0; i < s; i++) pos[nodes[i]] = i;\n\n        auto norm_dedup = [&](vector<pair<int,int>>& es) {\n            for (auto &e : es) if (e.first > e.second) swap(e.first, e.second);\n            sort(es.begin(), es.end());\n            es.erase(unique(es.begin(), es.end()), es.end());\n        };\n\n        vector<pair<int,int>> qE = queryEdges[k];\n        vector<pair<int,int>> fb = fallbackEdges[k];\n        norm_dedup(qE);\n        norm_dedup(fb);\n\n        int Kwin = (s >= 180 ? 7 : (s >= 90 ? 5 : 4));\n        vector<pair<int,int>> nb = build_neighbor_edges(nodes, Kwin);\n        norm_dedup(nb);\n\n        vector<CandEdge> cand;\n        cand.reserve(qE.size() + nb.size() + fb.size());\n\n        auto add_list = [&](const vector<pair<int,int>>& es, uint8_t tp) {\n            for (auto &e : es) {\n                int a = e.first, b = e.second;\n                if (pos[a] < 0 || pos[b] < 0) continue;\n                cand.push_back({a, b, lbdist(a,b), cdist(a,b), tp});\n            }\n        };\n        add_list(qE, 0);\n        add_list(nb, 1);\n        add_list(fb, 2);\n\n        sort(cand.begin(), cand.end(), [&](const CandEdge& A, const CandEdge& B){\n            if (A.tp != B.tp) return A.tp < B.tp;\n            if (A.lb != B.lb) return A.lb < B.lb;\n            if (A.cd != B.cd) return A.cd < B.cd;\n            if (A.a != B.a) return A.a < B.a;\n            return A.b < B.b;\n        });\n\n        atcoder::dsu dsu(s);\n        vector<pair<int,int>> res;\n        res.reserve(s - 1);\n\n        for (auto &e : cand) {\n            int pa = pos[e.a], pb = pos[e.b];\n            if (pa < 0 || pb < 0) continue;\n            if (dsu.same(pa, pb)) continue;\n            dsu.merge(pa, pb);\n            int a = e.a, b = e.b;\n            if (a > b) swap(a, b);\n            res.emplace_back(a, b);\n            if ((int)res.size() == s - 1) break;\n        }\n\n        if ((int)res.size() != s - 1) {\n            res = fb;\n            if ((int)res.size() != s - 1) {\n                res.clear();\n                for (int i = 1; i < s; i++) {\n                    int a = nodes[i-1], b = nodes[i];\n                    if (a > b) swap(a, b);\n                    res.emplace_back(a, b);\n                }\n            }\n        }\n        return res;\n    }\n\n    // Improved centroid swap: pick u far in worst group; choose v by sampling to minimize resulting total SSE\n    void centroid_swap_refine(mt19937 &rng, int ms_limit) {\n        int start = timer.ms();\n        if (ms_limit <= 0) return;\n\n        vector<int> posIn(N);\n        for (int k = 0; k < M; k++) for (int i = 0; i < (int)groups[k].size(); i++) posIn[groups[k][i]] = i;\n\n        vector<int> sz(M);\n        vector<long double> sx(M), sy(M), sxx(M), syy(M), sse(M);\n\n        for (int k = 0; k < M; k++) {\n            sz[k] = (int)groups[k].size();\n            long double ax=0, ay=0, axx=0, ayy=0;\n            for (int v : groups[k]) {\n                long double x = cities[v].cx, y = cities[v].cy;\n                ax += x; ay += y;\n                axx += x*x; ayy += y*y;\n            }\n            sx[k]=ax; sy[k]=ay; sxx[k]=axx; syy[k]=ayy;\n        }\n        auto calc_sse = [&](int k)->long double {\n            int s = sz[k];\n            if (s <= 1) return 0;\n            return (sxx[k] - sx[k]*sx[k]/s) + (syy[k] - sy[k]*sy[k]/s);\n        };\n        for (int k = 0; k < M; k++) sse[k] = calc_sse(k);\n\n        auto centroid = [&](int k)->pair<long double,long double> {\n            int s = max(1, sz[k]);\n            return {sx[k]/s, sy[k]/s};\n        };\n\n        auto eval_group_after = [&](int g, int remCity, int addCity)->long double {\n            int s = sz[g];\n            long double xR = cities[remCity].cx, yR = cities[remCity].cy;\n            long double xA = cities[addCity].cx, yA = cities[addCity].cy;\n            long double nsx = sx[g] - xR + xA;\n            long double nsy = sy[g] - yR + yA;\n            long double nsxx = sxx[g] - xR*xR + xA*xA;\n            long double nsyy = syy[g] - yR*yR + yA*yA;\n            if (s <= 1) return 0;\n            return (nsxx - nsx*nsx/s) + (nsyy - nsy*nsy/s);\n        };\n        auto apply_stats = [&](int g, int remCity, int addCity) {\n            long double xR = cities[remCity].cx, yR = cities[remCity].cy;\n            long double xA = cities[addCity].cx, yA = cities[addCity].cy;\n            sx[g] += -xR + xA;\n            sy[g] += -yR + yA;\n            sxx[g] += -(xR*xR) + (xA*xA);\n            syy[g] += -(yR*yR) + (yA*yA);\n            sse[g] = calc_sse(g);\n        };\n\n        vector<int> worst;\n        vector<vector<int>> nearG;\n        auto rebuild_lists = [&](){\n            worst.clear();\n            worst.reserve(M);\n            for (int k = 0; k < M; k++) worst.push_back(k);\n            sort(worst.begin(), worst.end(), [&](int a, int b){\n                if (sse[a] != sse[b]) return sse[a] > sse[b];\n                return a < b;\n            });\n            int topT = min(M, 40);\n            worst.resize(topT);\n\n            nearG.assign(M, {});\n            vector<pair<long double,long double>> cent(M);\n            for (int k = 0; k < M; k++) cent[k] = centroid(k);\n\n            for (int g : worst) {\n                vector<pair<long double,int>> ds;\n                ds.reserve(M-1);\n                auto [cx,cy] = cent[g];\n                for (int k = 0; k < M; k++) if (k != g) {\n                    auto [dx,dy] = cent[k];\n                    long double dd = (cx-dx)*(cx-dx) + (cy-dy)*(cy-dy);\n                    ds.push_back({dd,k});\n                }\n                int take = min(12, (int)ds.size());\n                nth_element(ds.begin(), ds.begin()+take, ds.end());\n                ds.resize(take);\n                sort(ds.begin(), ds.end());\n                nearG[g].reserve(take);\n                for (auto &p : ds) nearG[g].push_back(p.second);\n            }\n        };\n        rebuild_lists();\n\n        auto pick_far_city = [&](int g)->int {\n            int s = sz[g];\n            uniform_int_distribution<int> uid(0, s-1);\n            auto [cx,cy] = centroid(g);\n            int best = groups[g][uid(rng)];\n            long double bestd = -1;\n            for (int t = 0; t < 6; t++) {\n                int v = groups[g][uid(rng)];\n                long double dx = cities[v].cx - cx;\n                long double dy = cities[v].cy - cy;\n                long double d2 = dx*dx + dy*dy;\n                if (d2 > bestd) { bestd = d2; best = v; }\n            }\n            return best;\n        };\n\n        int iter = 0;\n        while (timer.ms() - start < ms_limit && time_ok()) {\n            if ((iter % 350) == 0) rebuild_lists();\n\n            int g1 = worst[uniform_int_distribution<int>(0, (int)worst.size()-1)(rng)];\n            if (sz[g1] <= 1) { iter++; continue; }\n            int u = pick_far_city(g1);\n\n            // try several neighbor groups, pick best swap\n            int best_g2 = -1, best_v = -1;\n            long double best_new = sse[g1];\n            long double best_new2 = 0;\n            long double cur_pair = 0;\n\n            int g2_trials = min(4, (int)nearG[g1].size());\n            if (g2_trials == 0) { iter++; continue; }\n\n            for (int tt = 0; tt < g2_trials; tt++) {\n                int g2 = nearG[g1][uniform_int_distribution<int>(0, (int)nearG[g1].size()-1)(rng)];\n                if (g2 == g1 || sz[g2] <= 1) continue;\n\n                long double old = sse[g1] + sse[g2];\n                // sample candidates v from g2; choose one minimizing new total sse\n                uniform_int_distribution<int> uid2(0, sz[g2]-1);\n                int samples = min(14, sz[g2]);\n                int local_best_v = groups[g2][uid2(rng)];\n                long double local_best = 1e100;\n\n                for (int s = 0; s < samples; s++) {\n                    int v = groups[g2][uid2(rng)];\n                    if (v == u) continue;\n                    long double ng1 = eval_group_after(g1, u, v);\n                    long double ng2 = eval_group_after(g2, v, u);\n                    long double neu = ng1 + ng2;\n                    if (neu < local_best) {\n                        local_best = neu;\n                        local_best_v = v;\n                    }\n                }\n                if (local_best + 1e-9 < old) {\n                    // compare by improvement\n                    if (best_g2 == -1 || local_best < cur_pair) {\n                        best_g2 = g2;\n                        best_v = local_best_v;\n                        best_new = eval_group_after(g1, u, best_v);\n                        best_new2 = eval_group_after(g2, best_v, u);\n                        cur_pair = local_best;\n                    }\n                }\n            }\n\n            if (best_g2 != -1) {\n                int g2 = best_g2;\n                int v = best_v;\n                int i1 = posIn[u];\n                int i2 = posIn[v];\n                groups[g1][i1] = v;\n                groups[g2][i2] = u;\n                posIn[v] = i1;\n                posIn[u] = i2;\n                apply_stats(g1, u, v);\n                apply_stats(g2, v, u);\n            }\n\n            iter++;\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        cities.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto &c = cities[i];\n            cin >> c.lx >> c.rx >> c.ly >> c.ry;\n            c.cx = (c.lx + c.rx) / 2;\n            c.cy = (c.ly + c.ry) / 2;\n            uint32_t x = (uint32_t)min(16383, max(0, c.cx));\n            uint32_t y = (uint32_t)min(16383, max(0, c.cy));\n            c.morton = morton2D(x, y);\n        }\n\n        // matrices\n        centerMat.assign((size_t)N * N, 0);\n        lbMat.assign((size_t)N * N, 0);\n        for (int i = 0; i < N; i++) {\n            centerMat[i*N+i] = 0;\n            lbMat[i*N+i] = 0;\n            for (int j = i+1; j < N; j++) {\n                long long dx = cities[i].cx - cities[j].cx;\n                long long dy = cities[i].cy - cities[j].cy;\n                long long sq = dx*dx + dy*dy;\n                int d = (int)floor(sqrt((double)sq));\n                d = max(0, min(65535, d));\n                centerMat[i*N+j] = centerMat[j*N+i] = (uint16_t)d;\n\n                long long ddx = 0, ddy = 0;\n                if (cities[i].rx < cities[j].lx) ddx = (long long)cities[j].lx - cities[i].rx;\n                else if (cities[j].rx < cities[i].lx) ddx = (long long)cities[i].lx - cities[j].rx;\n                if (cities[i].ry < cities[j].ly) ddy = (long long)cities[j].ly - cities[i].ry;\n                else if (cities[j].ry < cities[i].ly) ddy = (long long)cities[i].ly - cities[j].ry;\n                long long sq2 = ddx*ddx + ddy*ddy;\n                int lb = isqrt_floor_ll(sq2);\n                lb = max(0, min(65535, lb));\n                lbMat[i*N+j] = lbMat[j*N+i] = (uint16_t)lb;\n            }\n        }\n\n        // RNG\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < N; i++) {\n            seed ^= (uint64_t)cities[i].lx + 10007ULL*(uint64_t)cities[i].ly + 1000003ULL*(uint64_t)cities[i].rx;\n            seed *= 1099511628211ULL;\n        }\n        mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n        // orders\n        vector<int> ord_m(N), ord_x(N), ord_y(N), ord_xy1(N), ord_xy2(N);\n        iota(ord_m.begin(), ord_m.end(), 0);\n        iota(ord_x.begin(), ord_x.end(), 0);\n        iota(ord_y.begin(), ord_y.end(), 0);\n        iota(ord_xy1.begin(), ord_xy1.end(), 0);\n        iota(ord_xy2.begin(), ord_xy2.end(), 0);\n\n        sort(ord_m.begin(), ord_m.end(), [&](int a, int b){\n            if (cities[a].morton != cities[b].morton) return cities[a].morton < cities[b].morton;\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_x.begin(), ord_x.end(), [&](int a, int b){\n            if (cities[a].cx != cities[b].cx) return cities[a].cx < cities[b].cx;\n            return cities[a].cy < cities[b].cy;\n        });\n        sort(ord_y.begin(), ord_y.end(), [&](int a, int b){\n            if (cities[a].cy != cities[b].cy) return cities[a].cy < cities[b].cy;\n            return cities[a].cx < cities[b].cx;\n        });\n        sort(ord_xy1.begin(), ord_xy1.end(), [&](int a, int b){\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            return a < b;\n        });\n        sort(ord_xy2.begin(), ord_xy2.end(), [&](int a, int b){\n            int da = cities[a].cx - cities[a].cy;\n            int db = cities[b].cx - cities[b].cy;\n            if (da != db) return da < db;\n            int sa = cities[a].cx + cities[a].cy;\n            int sb = cities[b].cx + cities[b].cy;\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n\n        auto make_sampled_morton_order = [&]() {\n            vector<pair<uint32_t,int>> tmp;\n            tmp.reserve(N);\n            for (int i = 0; i < N; i++) {\n                uniform_int_distribution<int> dx(cities[i].lx, cities[i].rx);\n                uniform_int_distribution<int> dy(cities[i].ly, cities[i].ry);\n                int x = dx(rng), y = dy(rng);\n                uint32_t key = morton2D((uint32_t)min(16383, max(0, x)), (uint32_t)min(16383, max(0, y)));\n                tmp.push_back({key, i});\n            }\n            sort(tmp.begin(), tmp.end(), [&](auto &A, auto &B){\n                if (A.first != B.first) return A.first < B.first;\n                return A.second < B.second;\n            });\n            vector<int> ord; ord.reserve(N);\n            for (auto &p : tmp) ord.push_back(p.second);\n            return ord;\n        };\n        vector<int> ord_s1 = make_sampled_morton_order();\n        vector<int> ord_s2 = make_sampled_morton_order();\n\n        // group orders\n        vector<int> go_given(M), go_desc(M);\n        iota(go_given.begin(), go_given.end(), 0);\n        iota(go_desc.begin(), go_desc.end(), 0);\n        sort(go_desc.begin(), go_desc.end(), [&](int a, int b){\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        // candidates: best-known set + a low-risk reversed Morton sweep\n        vector<vector<vector<int>>> candidates;\n        candidates.reserve(18);\n\n        candidates.push_back(build_groups_sweep(ord_m, go_desc));\n        candidates.push_back(build_groups_sweep(ord_m, go_given));\n        candidates.push_back(build_groups_sweep(ord_x, go_given));\n        candidates.push_back(build_groups_sweep(ord_y, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy1, go_given));\n        candidates.push_back(build_groups_sweep(ord_xy2, go_given));\n        candidates.push_back(build_groups_sweep(ord_s1, go_given));\n        candidates.push_back(build_groups_sweep(ord_s2, go_given));\n\n        // reversed Morton (can fix boundary direction issues)\n        {\n            vector<int> revm = ord_m;\n            reverse(revm.begin(), revm.end());\n            candidates.push_back(build_groups_sweep(revm, go_given));\n        }\n\n        candidates.push_back(build_groups_grow(ord_m, go_desc));\n        candidates.push_back(build_groups_grow(ord_m, go_given));\n        candidates.push_back(build_groups_grow(ord_x, go_desc));\n        candidates.push_back(build_groups_grow(ord_y, go_desc));\n\n        for (int t = 0; t < 2; t++) {\n            vector<int> go = go_desc;\n            shuffle(go.begin(), go.end(), rng);\n            candidates.push_back(build_groups_grow(ord_m, go));\n        }\n\n        // selection: best center MST, tie-break LB within margin\n        vector<long long> cscore(candidates.size());\n        long long bestC = (1LL<<62);\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            long long cs = 0;\n            for (int k = 0; k < M; k++) cs += prim_sum(candidates[i][k], centerMat.data());\n            cscore[i] = cs;\n            bestC = min(bestC, cs);\n        }\n        long long margin = max(3000LL, bestC / 300); // ~0.33%\n        long long bestLb = (1LL<<62);\n        int chosen = -1;\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (cscore[i] > bestC + margin) continue;\n            long long lb = 0;\n            for (int k = 0; k < M; k++) lb += prim_sum(candidates[i][k], lbMat.data());\n            if (lb < bestLb || (lb == bestLb && (chosen == -1 || cscore[i] < cscore[chosen]))) {\n                bestLb = lb;\n                chosen = i;\n            }\n        }\n        if (chosen == -1) chosen = (int)(min_element(cscore.begin(), cscore.end()) - cscore.begin());\n        groups = move(candidates[chosen]);\n\n        // centroid refine (time-limited), validate by MST proxy\n        auto original_groups = groups;\n        long long origCenterMST = 0;\n        for (int k = 0; k < M; k++) origCenterMST += prim_sum(groups[k], centerMat.data());\n\n        // adaptive budget\n        int budget = min(300, max(180, TIME_GUARD_MS - timer.ms() - 520));\n        if (budget > 0 && time_ok()) centroid_swap_refine(rng, budget);\n\n        long long newCenterMST = 0;\n        for (int k = 0; k < M; k++) newCenterMST += prim_sum(groups[k], centerMat.data());\n        if (newCenterMST > origCenterMST + origCenterMST / 300) {\n            groups = move(original_groups);\n        }\n\n        // fallback MST per group + max edge\n        fallbackEdges.assign(M, {});\n        fallbackEdgesW.assign(M, {});\n        groupEstCost.assign(M, 0);\n        groupMaxEdge.assign(M, 0);\n        for (int k = 0; k < M; k++) {\n            groupEstCost[k] = prim_build_center_edges(groups[k], fallbackEdges[k], fallbackEdgesW[k]);\n            int mx = 0;\n            for (auto &e : fallbackEdgesW[k]) mx = max(mx, (int)e.w);\n            groupMaxEdge[k] = mx;\n        }\n\n        // ---- Query phase ----\n        queryEdges.assign(M, {});\n        fullQueried.assign(M, false);\n        q_used = 0;\n\n        int num_large = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) num_large++;\n\n        int reserve_for_large = 0;\n        if (num_large > 0) reserve_for_large = min(Q, max(60, min(Q * 2 / 3, num_large * 10)));\n        int small_query_limit = max(0, Q - reserve_for_large);\n\n        vector<int> small;\n        for (int k = 0; k < M; k++) {\n            int s = (int)groups[k].size();\n            if (s >= 3 && s <= L) small.push_back(k);\n        }\n        sort(small.begin(), small.end(), [&](int a, int b){\n            int sa = (int)groups[a].size(), sb = (int)groups[b].size();\n            if (sa != sb) return sa > sb;\n            if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n            return a < b;\n        });\n\n        for (int k : small) {\n            if (!time_ok()) break;\n            if (q_used >= small_query_limit) break;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        // large query allocation: mild max-edge bias\n        vector<int> large;\n        long long totalWeight = 0;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() > L) {\n            large.push_back(k);\n            long long w = groupEstCost[k] + 3LL * groupMaxEdge[k];\n            totalWeight += max(1LL, w);\n        }\n        sort(large.begin(), large.end(), [&](int a, int b){\n            long long wa = groupEstCost[a] + 3LL * groupMaxEdge[a];\n            long long wb = groupEstCost[b] + 3LL * groupMaxEdge[b];\n            if (wa != wb) return wa > wb;\n            return (int)groups[a].size() > (int)groups[b].size();\n        });\n\n        unordered_set<uint64_t> usedSub;\n        usedSub.reserve(512);\n\n        for (int k : large) {\n            if (!time_ok() || q_used >= Q) break;\n            int remaining = Q - q_used;\n\n            long long w = groupEstCost[k] + 3LL * groupMaxEdge[k];\n            if (w < 1) w = 1;\n\n            int myBudget = (int)llround((double)reserve_for_large * (double)w / (double)max(1LL, totalWeight));\n            myBudget = max(4, min(myBudget, 16));\n            myBudget = min(myBudget, remaining);\n\n            auto edgesW = fallbackEdgesW[k];\n            sort(edgesW.begin(), edgesW.end(), [&](const EdgeW& A, const EdgeW& B){ return A.w > B.w; });\n\n            int qi = 0;\n            int takeEdges = min((int)edgesW.size(), myBudget * 3);\n            for (int i = 0; i < takeEdges && qi < myBudget && q_used < Q; i++) {\n                if (!time_ok()) break;\n                int u = edgesW[i].a, v = edgesW[i].b;\n                auto subset = make_edge_subset(k, u, v);\n                if ((int)subset.size() < 3) continue;\n\n                uint64_t hs = subset_hash(subset);\n                if (usedSub.count(hs)) continue;\n                usedSub.insert(hs);\n\n                auto e = do_query(subset);\n                queryEdges[k].insert(queryEdges[k].end(), e.begin(), e.end());\n                qi++;\n            }\n        }\n\n        for (int k : small) {\n            if (!time_ok() || q_used >= Q) break;\n            if (fullQueried[k]) continue;\n            queryEdges[k] = do_query(groups[k]);\n            fullQueried[k] = true;\n        }\n\n        // ---- Output ----\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            auto edges = build_final_tree(k);\n            int need = (int)groups[k].size() - 1;\n            if ((int)edges.size() != need) edges = fallbackEdges[k];\n\n            for (auto &e : edges) {\n                int a = e.first, b = e.second;\n                if (a > b) swap(a, b);\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout << flush;\n    }\n};\n\nint main() {\n    Solver s;\n    s.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Action { char a, d; };\n\nstatic const int di[4] = {-1, 1, 0, 0};\nstatic const int dj[4] = {0, 0, -1, 1};\nstatic const char dirc[4] = {'U','D','L','R'};\nstatic const char actc[3] = {'M','S','A'};\n\nstruct SplitMix64 {\n    uint64_t x;\n    explicit SplitMix64(uint64_t seed=0) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n};\n\nstruct Solver {\n    int N, M;\n    vector<pair<int,int>> P;\n    int ord[20][20];\n\n    // Local BFS dimensions\n    static constexpr int NN = 400;\n    static constexpr int KMAX = 13;\n    static constexpr int EXTRA_BUDGET = 3;\n    static constexpr double TIME_LIMIT = 1.92;\n    static constexpr int MULTI_START_MAX = 3;\n\n    static constexpr int MAX_STATES = NN * (1 << KMAX);\n    vector<int16_t> distBuf;\n    vector<int32_t> prevBuf;\n    vector<uint8_t> prevOpBuf;\n    vector<int> visitedStates;\n    vector<int> q;\n    vector<uint8_t> popAll;\n\n    using Clock = chrono::steady_clock;\n    Clock::time_point t0;\n\n    struct Params {\n        int maxBlocks;     // hard cap for local BFS / acceptance\n        int penaltyStart;  // start penalizing above this\n    };\n\n    Solver() {\n        distBuf.assign(MAX_STATES, -1);\n        prevBuf.resize(MAX_STATES);\n        prevOpBuf.resize(MAX_STATES);\n        visitedStates.reserve(1<<20);\n        q.reserve(1<<20);\n\n        popAll.assign(1<<KMAX, 0);\n        for (int m = 1; m < (1<<KMAX); m++) popAll[m] = popAll[m>>1] + (m&1);\n\n        for(int i=0;i<20;i++) for(int j=0;j<20;j++) ord[i][j] = -1;\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(Clock::now() - t0).count();\n    }\n\n    inline bool inside(int x,int y) const { return 0<=x && x<N && 0<=y && y<N; }\n    inline int posId(int x,int y) const { return x*N + y; }\n    inline pair<int,int> idPos(int id) const { return {id/N, id%N}; }\n\n    inline bool forbiddenCell(int x,int y,int curIndex) const {\n        int t = ord[x][y];\n        return (t != -1 && t > curIndex); // current/future targets forbidden\n    }\n    inline bool pastTargetCell(int x,int y,int curIndex) const {\n        int t = ord[x][y];\n        return (t != -1 && t <= curIndex);\n    }\n\n    // ---- fixed BFS (Move+Slide) ----\n    inline int slideStop(const uint8_t b[20][20], int x, int y, int dir) const {\n        int nx=x, ny=y;\n        while(true){\n            int tx=nx+di[dir], ty=ny+dj[dir];\n            if(!inside(tx,ty)) break;\n            if(b[tx][ty]) break;\n            nx=tx; ny=ty;\n        }\n        return posId(nx,ny);\n    }\n\n    int shortestFixedLen(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S=posId(s.first,s.second);\n        int G=posId(g.first,g.second);\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> qq;\n        int head=0, tail=0;\n        dist[S]=0; qq[tail++]=S;\n        while(head<tail){\n            int v=qq[head++];\n            if(v==G) return dist[v];\n            auto [x,y]=idPos(v);\n            for(int d=0; d<4; d++){\n                int mx=x+di[d], my=y+dj[d];\n                if(inside(mx,my) && !b[mx][my]){\n                    int to=posId(mx,my);\n                    if(dist[to]==-1){ dist[to]=dist[v]+1; qq[tail++]=to; }\n                }\n                int to=slideStop(b,x,y,d);\n                if(to!=v && dist[to]==-1){ dist[to]=dist[v]+1; qq[tail++]=to; }\n            }\n        }\n        return 1e9;\n    }\n\n    vector<Action> shortestFixedPath(const uint8_t b[20][20], pair<int,int> s, pair<int,int> g) const {\n        int S=posId(s.first,s.second);\n        int G=posId(g.first,g.second);\n\n        array<int16_t, NN> dist;\n        dist.fill(-1);\n        array<int, NN> prev;\n        prev.fill(-1);\n        array<uint8_t, NN> prevOp;\n        prevOp.fill(255);\n\n        array<int, NN> qq;\n        int head=0, tail=0;\n\n        dist[S]=0; qq[tail++]=S;\n        while(head<tail){\n            int v=qq[head++];\n            if(v==G) break;\n            auto [x,y]=idPos(v);\n\n            for(int d=0; d<4; d++){\n                int mx=x+di[d], my=y+dj[d];\n                if(inside(mx,my) && !b[mx][my]){\n                    int to=posId(mx,my);\n                    if(dist[to]==-1){\n                        dist[to]=dist[v]+1;\n                        prev[to]=v;\n                        prevOp[to]=(0*4+d);\n                        qq[tail++]=to;\n                    }\n                }\n                int to=slideStop(b,x,y,d);\n                if(to!=v && dist[to]==-1){\n                    dist[to]=dist[v]+1;\n                    prev[to]=v;\n                    prevOp[to]=(1*4+d);\n                    qq[tail++]=to;\n                }\n            }\n        }\n        if(dist[G]==-1) return {};\n\n        vector<Action> res;\n        for(int cur=G; cur!=S; cur=prev[cur]){\n            uint8_t code=prevOp[cur];\n            int a=code/4, d=code%4;\n            res.push_back(Action{actc[a], dirc[d]});\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    // ---- apply action ----\n    inline void applyAction(uint8_t b[20][20], int &totBlocks, pair<int,int> &cur, const Action &ac) const {\n        int d=0; while(d<4 && dirc[d]!=ac.d) d++;\n        int x=cur.first, y=cur.second;\n        if(ac.a=='M'){\n            cur={x+di[d], y+dj[d]};\n        }else if(ac.a=='S'){\n            int nx=x, ny=y;\n            while(true){\n                int tx=nx+di[d], ty=ny+dj[d];\n                if(!inside(tx,ty)) break;\n                if(b[tx][ty]) break;\n                nx=tx; ny=ty;\n            }\n            cur={nx,ny};\n        }else{ // 'A'\n            int ax=x+di[d], ay=y+dj[d];\n            if(!inside(ax,ay)) return;\n            bool before=b[ax][ay];\n            b[ax][ay]^=1;\n            if(!before && b[ax][ay]) totBlocks++;\n            if(before && !b[ax][ay]) totBlocks--;\n        }\n    }\n\n    // ---- connectivity check (plain move BFS) ----\n    bool allRemainingReachable(const uint8_t b[20][20], pair<int,int> startPos, int lastVisitedIndex) const {\n        static int vis[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) vis[i][j]=0;\n\n        if(b[startPos.first][startPos.second]) return false;\n\n        deque<pair<int,int>> dq;\n        vis[startPos.first][startPos.second]=1;\n        dq.push_back(startPos);\n\n        while(!dq.empty()){\n            auto [x,y]=dq.front(); dq.pop_front();\n            for(int d=0; d<4; d++){\n                int nx=x+di[d], ny=y+dj[d];\n                if(!inside(nx,ny)) continue;\n                if(vis[nx][ny]) continue;\n                if(b[nx][ny]) continue;\n                vis[nx][ny]=1;\n                dq.push_back({nx,ny});\n            }\n        }\n\n        for(int idx = lastVisitedIndex+1; idx < M; idx++){\n            auto [tx,ty]=P[idx];\n            if(!vis[tx][ty]) return false;\n        }\n        return true;\n    }\n\n    inline int blockPenaltyScaled2(int totBlocks, const Params& ps) const {\n        if(totBlocks <= ps.penaltyStart) return 0;\n        return (totBlocks - ps.penaltyStart) * 2;\n    }\n\n    // Baseline slide blocker cells (beyond stop points)\n    void addBaselineSlideBlockers(const uint8_t b[20][20], pair<int,int> s,\n                                 const vector<Action>& basePath,\n                                 int curIndex, int pr[20][20],\n                                 SplitMix64 &rng) const {\n        auto noise = [&](int x,int y)->int{\n            uint64_t h = (uint64_t)(x*31 + y*131 + 0x9e3779b9);\n            h ^= rng.x + 0xD1B54A32D192ED03ULL;\n            h ^= (h<<7) ^ (h>>9);\n            return (int)(h % 7) - 3;\n        };\n\n        auto addCand = [&](int x,int y,int p){\n            if(!inside(x,y)) return;\n            if(forbiddenCell(x,y,curIndex)) return;\n            if(pastTargetCell(x,y,curIndex)) p += 25;\n            p += noise(x,y);\n            pr[x][y] = max(pr[x][y], p);\n        };\n\n        pair<int,int> cur = s;\n        for(const auto &ac: basePath){\n            int d=0; while(d<4 && dirc[d]!=ac.d) d++;\n            if(ac.a=='S'){\n                int nx=cur.first, ny=cur.second;\n                while(true){\n                    int tx=nx+di[d], ty=ny+dj[d];\n                    if(!inside(tx,ty)) break;\n                    if(b[tx][ty]) break;\n                    nx=tx; ny=ty;\n                }\n                int bx = nx + di[d], by = ny + dj[d];\n                addCand(bx, by, 110); // moderate\n                cur = {nx, ny};\n            } else if(ac.a=='M') {\n                cur = {cur.first + di[d], cur.second + dj[d]};\n            }\n        }\n    }\n\n    // local BFS: returns plan and its 2-step objective; INT_MAX if none\n    pair<vector<Action>, int> bestLocalPlan2Step(\n        SplitMix64 &rng,\n        int curIndex,\n        const Params& ps,\n        const uint8_t baseB[20][20],\n        int baseTotalBlocks,\n        pair<int,int> s, pair<int,int> g,\n        const vector<Action>& basePath,\n        bool has2, pair<int,int> t2,\n        bool has3, pair<int,int> t3\n    ){\n        if (basePath.empty()) return {{}, INT_MAX};\n        int baselineLen = (int)basePath.size();\n        if (baselineLen <= 1) return {{}, INT_MAX};\n        if (elapsed() > TIME_LIMIT) return {{}, INT_MAX};\n\n        int pr[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) pr[i][j]=-1;\n\n        auto noise = [&](int x,int y)->int{\n            uint64_t h = (uint64_t)(x*31 + y*131 + 0x9e3779b9);\n            h ^= rng.x + 0xD1B54A32D192ED03ULL;\n            h ^= (h<<7) ^ (h>>9);\n            return (int)(h % 7) - 3;\n        };\n\n        auto addCand = [&](int x,int y,int p){\n            if(!inside(x,y)) return;\n            if(forbiddenCell(x,y,curIndex)) return;\n            if(pastTargetCell(x,y,curIndex)) p += 35;\n            p += noise(x,y);\n            pr[x][y]=max(pr[x][y], p);\n        };\n\n        int sx=s.first, sy=s.second, gx=g.first, gy=g.second;\n\n        // Around goal\n        for(int d=0; d<4; d++){\n            addCand(gx+di[d], gy+dj[d], 240);\n            addCand(gx+2*di[d], gy+2*dj[d], 170);\n        }\n        for(int dx=-3; dx<=3; dx++) for(int dy=-3; dy<=3; dy++){\n            if(abs(dx)+abs(dy)<=3) addCand(gx+dx, gy+dy, 135);\n        }\n\n        // Around start\n        for(int d=0; d<4; d++) addCand(sx+di[d], sy+dj[d], 150);\n        for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n            if(abs(dx)+abs(dy)<=2) addCand(sx+dx, sy+dy, 100);\n        }\n\n        // L corners\n        int c1x=sx, c1y=gy;\n        int c2x=gx, c2y=sy;\n        for(int dx=-1; dx<=1; dx++) for(int dy=-1; dy<=1; dy++){\n            addCand(c1x+dx, c1y+dy, 125);\n            addCand(c2x+dx, c2y+dy, 125);\n        }\n\n        // Existing blocks near start/goal\n        for(int dx=-3; dx<=3; dx++) for(int dy=-3; dy<=3; dy++){\n            int x=gx+dx, y=gy+dy;\n            if(inside(x,y) && baseB[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x,y,150);\n        }\n        for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n            int x=sx+dx, y=sy+dy;\n            if(inside(x,y) && baseB[x][y] && !forbiddenCell(x,y,curIndex)) addCand(x,y,110);\n        }\n\n        // Future hints\n        auto addFuture = [&](pair<int,int> t, int base){\n            int x=t.first, y=t.second;\n            for(int d=0; d<4; d++) addCand(x+di[d], y+dj[d], base);\n            for(int dx=-2; dx<=2; dx++) for(int dy=-2; dy<=2; dy++){\n                if(abs(dx)+abs(dy)<=2) addCand(x+dx, y+dy, base-25);\n            }\n        };\n        if(has2) addFuture(t2, 70);\n        if(has3) addFuture(t3, 55);\n\n        // Minimal extra: baseline slide blocker cells\n        addBaselineSlideBlockers(baseB, s, basePath, curIndex, pr, rng);\n\n        struct C{int p,x,y;};\n        vector<C> cand;\n        cand.reserve(250);\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(pr[i][j]>=0) cand.push_back({pr[i][j],i,j});\n        if(cand.empty()) return {{}, INT_MAX};\n\n        sort(cand.begin(), cand.end(), [&](const C& a, const C& b){\n            if(a.p!=b.p) return a.p>b.p;\n            int mx=(sx+gx)/2, my=(sy+gy)/2;\n            int da=abs(a.x-mx)+abs(a.y-my);\n            int db=abs(b.x-mx)+abs(b.y-my);\n            if(da!=db) return da<db;\n            if(a.x!=b.x) return a.x<b.x;\n            return a.y<b.y;\n        });\n\n        int K=min((int)cand.size(), KMAX);\n        cand.resize(K);\n        int MSZ=1<<K;\n\n        int idx[20][20];\n        for(int i=0;i<N;i++) for(int j=0;j<N;j++) idx[i][j]=-1;\n        for(int t=0;t<K;t++) idx[cand[t].x][cand[t].y]=t;\n\n        int initMask=0;\n        for(int t=0;t<K;t++) if(baseB[cand[t].x][cand[t].y]) initMask |= (1<<t);\n        int baseOutside = baseTotalBlocks - popAll[initMask];\n\n        auto sid = [&](int mask,int pos){ return mask*NN + pos; };\n\n        auto isBlocked = [&](int x,int y,int mask)->bool{\n            if(!inside(x,y)) return true;\n            int t=idx[x][y];\n            if(t>=0) return (mask>>t)&1;\n            return baseB[x][y];\n        };\n\n        auto slideStopMask = [&](int x,int y,int dir,int mask)->int{\n            int nx=x, ny=y;\n            while(true){\n                int tx=nx+di[dir], ty=ny+dj[dir];\n                if(!inside(tx,ty)) break;\n                if(isBlocked(tx,ty,mask)) break;\n                nx=tx; ny=ty;\n            }\n            return posId(nx,ny);\n        };\n\n        int Spos=posId(s.first,s.second);\n        int Gpos=posId(g.first,g.second);\n        int limit = baselineLen + EXTRA_BUDGET;\n\n        visitedStates.clear();\n        q.clear();\n\n        auto pushState = [&](int id,int16_t d,int32_t parent,uint8_t op){\n            distBuf[id]=d;\n            prevBuf[id]=parent;\n            prevOpBuf[id]=op;\n            visitedStates.push_back(id);\n            q.push_back(id);\n        };\n\n        int s0 = sid(initMask, Spos);\n        pushState(s0, 0, -1, 255);\n\n        size_t head=0;\n        while(head<q.size()){\n            int v=q[head++];\n            int16_t dcur=distBuf[v];\n            if(dcur>=limit) continue;\n\n            int mask=v/NN;\n            int pos=v%NN;\n            auto [x,y]=idPos(pos);\n\n            // Move/Slide\n            for(int dd=0; dd<4; dd++){\n                int mx=x+di[dd], my=y+dj[dd];\n                if(inside(mx,my) && !isBlocked(mx,my,mask)){\n                    int to=sid(mask, posId(mx,my));\n                    if(distBuf[to]==-1) pushState(to, dcur+1, v, (0*4+dd));\n                }\n                int sp=slideStopMask(x,y,dd,mask);\n                if(sp!=pos){\n                    int to=sid(mask, sp);\n                    if(distBuf[to]==-1) pushState(to, dcur+1, v, (1*4+dd));\n                }\n            }\n\n            // Alter adjacent candidate only\n            for(int dd=0; dd<4; dd++){\n                int ax=x+di[dd], ay=y+dj[dd];\n                if(!inside(ax,ay)) continue;\n                int t=idx[ax][ay];\n                if(t<0) continue;\n                if(forbiddenCell(ax,ay,curIndex)) continue;\n\n                int nmask = mask ^ (1<<t);\n                int totTemp = baseOutside + popAll[nmask];\n                if(totTemp > ps.maxBlocks) continue;\n\n                int to=sid(nmask, pos);\n                if(distBuf[to]==-1) pushState(to, dcur+1, v, (2*4+dd));\n            }\n        }\n\n        uint8_t tempB[20][20];\n\n        int bestObj = INT_MAX;\n        int bestId = -1;\n        int bestD1 = INT_MAX;\n        int bestBlocks = INT_MAX;\n\n        for(int mask=0; mask<MSZ; mask++){\n            int id=sid(mask, Gpos);\n            int16_t d1=distBuf[id];\n            if(d1==-1 || d1>limit) continue;\n\n            memcpy(tempB, baseB, sizeof(tempB));\n            for(int t=0;t<K;t++) tempB[cand[t].x][cand[t].y] = (mask>>t)&1;\n\n            int d2=0, d3=0;\n            if(has2) d2 = shortestFixedLen(tempB, g, t2);\n            if(has3) d3 = shortestFixedLen(tempB, t2, t3);\n\n            int totBlocksTemp = baseOutside + popAll[mask];\n            int obj = 2*((int)d1 + d2) + d3 + blockPenaltyScaled2(totBlocksTemp, ps);\n\n            if(obj < bestObj ||\n               (obj==bestObj && (int)d1 < bestD1) ||\n               (obj==bestObj && (int)d1==bestD1 && totBlocksTemp < bestBlocks)){\n                bestObj = obj;\n                bestId = id;\n                bestD1 = (int)d1;\n                bestBlocks = totBlocksTemp;\n            }\n        }\n\n        vector<Action> res;\n        if(bestId != -1){\n            int curId = bestId;\n            while(curId != s0){\n                uint8_t code = prevOpBuf[curId];\n                int a=code/4, d=code%4;\n                res.push_back(Action{actc[a], dirc[d]});\n                curId = prevBuf[curId];\n                if(curId < 0) break;\n            }\n            reverse(res.begin(), res.end());\n        }\n\n        for(int id: visitedStates) distBuf[id] = -1;\n\n        if(res.empty()) return {{}, INT_MAX};\n        return {res, bestObj};\n    }\n\n    struct RunResult {\n        vector<Action> acts;\n        int visited = 0;\n        int turns = 0;\n    };\n\n    RunResult solveOne(uint64_t seed, const Params& ps) {\n        SplitMix64 rng(seed);\n\n        uint8_t b[20][20];\n        memset(b, 0, sizeof(b));\n        int totBlocks = 0;\n\n        pair<int,int> cur = P[0];\n        vector<Action> out;\n        out.reserve(750);\n\n        int visited = 0;\n\n        for(int k=0; k<M-1; k++){\n            if ((int)out.size() >= 2*N*M) break;\n\n            if (elapsed() > TIME_LIMIT) {\n                // finish greedily\n                for(int kk=k; kk<M-1; kk++){\n                    auto path = shortestFixedPath(b, cur, P[kk+1]);\n                    if(path.empty()) break;\n                    for(auto &ac: path){\n                        out.push_back(ac);\n                        applyAction(b, totBlocks, cur, ac);\n                        if ((int)out.size() >= 2*N*M) break;\n                    }\n                    if(cur == P[kk+1]) visited++;\n                    if ((int)out.size() >= 2*N*M) break;\n                }\n                break;\n            }\n\n            pair<int,int> goal = P[k+1];\n            bool has2 = (k+2 < M);\n            bool has3 = (k+3 < M);\n            pair<int,int> t2 = has2 ? P[k+2] : make_pair(-1,-1);\n            pair<int,int> t3 = has3 ? P[k+3] : make_pair(-1,-1);\n\n            auto basePath = shortestFixedPath(b, cur, goal);\n            if(basePath.empty()) break;\n            int baseLen = (int)basePath.size();\n\n            int d2=0, d3=0;\n            if(has2) d2 = shortestFixedLen(b, goal, t2);\n            if(has3) d3 = shortestFixedLen(b, t2, t3);\n            int baseObj = 2*(baseLen + d2) + d3 + blockPenaltyScaled2(totBlocks, ps);\n\n            auto [locPlan, locObj] = bestLocalPlan2Step(\n                rng, k, ps, b, totBlocks, cur, goal, basePath, has2, t2, has3, t3\n            );\n\n            const vector<Action>* use = &basePath;\n\n            // validate local plan (reach goal + block cap + connectivity)\n            if(!locPlan.empty()){\n                uint8_t tb[20][20];\n                memcpy(tb, b, sizeof(tb));\n                int tBlocks = totBlocks;\n                pair<int,int> tcur = cur;\n\n                for(auto &ac: locPlan) applyAction(tb, tBlocks, tcur, ac);\n\n                bool ok = true;\n                if(tcur != goal) ok = false;\n                if(tBlocks > ps.maxBlocks) ok = false;\n                if(ok && !allRemainingReachable(tb, tcur, k+1)) ok = false;\n\n                if(ok){\n                    // Use proven 2-step objective acceptance (stable best behavior).\n                    if(locObj < baseObj || (locObj==baseObj && (int)locPlan.size() < baseLen)){\n                        use = &locPlan;\n                    }\n                }\n            }\n\n            for(auto &ac: *use){\n                out.push_back(ac);\n                applyAction(b, totBlocks, cur, ac);\n                if ((int)out.size() >= 2*N*M) break;\n            }\n\n            if(cur == goal) visited++;\n            else break;\n        }\n\n        RunResult rr;\n        rr.acts = std::move(out);\n        rr.visited = visited;\n        rr.turns = (int)rr.acts.size();\n        return rr;\n    }\n\n    void solve() {\n        t0 = Clock::now();\n\n        // Run parameter diversification:\n        // - run0 strict => baseline protection\n        // - run1/run2 relaxed => sometimes more stoppers help\n        Params strict{120, 100};\n        Params relaxed{150, 110};\n\n        vector<pair<Params, uint64_t>> runs;\n        runs.reserve(MULTI_START_MAX);\n        runs.push_back({strict, 0x123456789abcdef0ULL});\n        runs.push_back({relaxed, 0x9e3779b97f4a7c15ULL});\n        runs.push_back({relaxed, 0xD1B54A32D192ED03ULL});\n\n        RunResult best;\n        best.visited = -1;\n        best.turns = INT_MAX;\n\n        for(int i=0;i<(int)runs.size();i++){\n            if(elapsed() > 1.88) break;\n\n            uint64_t seed = runs[i].second ^\n                (uint64_t)chrono::duration_cast<chrono::nanoseconds>(Clock::now().time_since_epoch()).count();\n\n            RunResult rr = solveOne(seed, runs[i].first);\n\n            if (rr.visited > best.visited || (rr.visited == best.visited && rr.turns < best.turns)) {\n                best = std::move(rr);\n            }\n        }\n\n        for (auto &ac : best.acts) {\n            cout << ac.a << ' ' << ac.d << \"\\n\";\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver s;\n    cin >> s.N >> s.M;\n    s.P.resize(s.M);\n    for(int k=0;k<s.M;k++){\n        int x,y; cin >> x >> y;\n        s.P[k] = {x,y};\n        s.ord[x][y] = k;\n    }\n    s.solve();\n    return 0;\n}"}}}